Skip to content

Commit

Permalink
added share button
Browse files Browse the repository at this point in the history
  • Loading branch information
DatL4g committed Apr 28, 2024
1 parent 765056a commit a4f1190
Show file tree
Hide file tree
Showing 12 changed files with 164 additions and 40 deletions.
3 changes: 2 additions & 1 deletion anilist/src/commonMain/graphql/AiringQuery.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ query AiringQuery(
id,
site,
thumbnail
}
},
siteUrl
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion anilist/src/commonMain/graphql/MediumQuery.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ query MediumQuery($id: Int, $statusVersion: Int, $html: Boolean) {
id,
site,
thumbnail
}
},
siteUrl
}
}
3 changes: 2 additions & 1 deletion anilist/src/commonMain/graphql/SeasonQuery.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ query SeasonQuery(
id,
site,
thumbnail
}
},
siteUrl
}
}
}
3 changes: 2 additions & 1 deletion anilist/src/commonMain/graphql/TrendingQuery.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ query TrendingQuery(
id,
site,
thumbnail
}
},
siteUrl
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ data class Medium(
val entry: Entry? = null,
val trailer: Trailer? = null,
val isFavorite: Boolean = false,
private val _isFavoriteBlocked: Boolean = true
private val _isFavoriteBlocked: Boolean = true,
val siteUrl: String = "$SITE_URL$id"
) {
constructor(trending: TrendingQuery.Medium) : this(
id = trending.id,
Expand Down Expand Up @@ -92,7 +93,8 @@ data class Medium(
}
},
isFavorite = trending.isFavourite,
_isFavoriteBlocked = trending.isFavouriteBlocked
_isFavoriteBlocked = trending.isFavouriteBlocked,
siteUrl = trending.siteUrl?.ifBlank { null } ?: "$SITE_URL${trending.id}"
)

constructor(airing: AiringQuery.Media) : this(
Expand Down Expand Up @@ -140,7 +142,8 @@ data class Medium(
}
},
isFavorite = airing.isFavourite,
_isFavoriteBlocked = airing.isFavouriteBlocked
_isFavoriteBlocked = airing.isFavouriteBlocked,
siteUrl = airing.siteUrl?.ifBlank { null } ?: "$SITE_URL${airing.id}"
)

constructor(season: SeasonQuery.Medium) : this(
Expand Down Expand Up @@ -188,7 +191,8 @@ data class Medium(
}
},
isFavorite = season.isFavourite,
_isFavoriteBlocked = season.isFavouriteBlocked
_isFavoriteBlocked = season.isFavouriteBlocked,
siteUrl = season.siteUrl?.ifBlank { null } ?: "$SITE_URL${season.id}"
)

constructor(query: MediumQuery.Media) : this(
Expand Down Expand Up @@ -236,7 +240,8 @@ data class Medium(
}
},
isFavorite = query.isFavourite,
_isFavoriteBlocked = query.isFavouriteBlocked
_isFavoriteBlocked = query.isFavouriteBlocked,
siteUrl = query.siteUrl?.ifBlank { null } ?: "$SITE_URL${query.id}"
)

@Transient
Expand Down Expand Up @@ -463,4 +468,8 @@ data class Medium(
airingAt = nextAiringEpisode.airingAt
)
}

companion object {
private const val SITE_URL = "https://anilist.co/"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package dev.datlag.aniflow.ui.custom

import android.content.Context
import android.content.Intent
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import androidx.core.content.ContextCompat

@Composable
actual fun shareHandler(): ShareHandler {
val context = LocalContext.current
return remember(context) {
ShareHandler(context)
}
}

actual class ShareHandler(
private val context: Context
) {
actual fun share(url: String?) {
if (!url.isNullOrBlank()) {
val intent = Intent(Intent.ACTION_SEND)
intent.type = "text/plain"
intent.putExtra(Intent.EXTRA_TEXT, url)

ContextCompat.startActivity(
context,
Intent.createChooser(intent, null),
null
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package dev.datlag.aniflow.ui.custom

import androidx.compose.runtime.Composable

@Composable
expect fun shareHandler(): ShareHandler

expect class ShareHandler {
fun share(url: String?)
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ interface MediumComponent : ContentHolderComponent {
val trailer: StateFlow<Medium.Trailer?>
val isFavorite: StateFlow<Boolean>
val isFavoriteBlocked: StateFlow<Boolean>
val siteUrl: StateFlow<String>

val bsAvailable: Boolean

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ fun MediumScreen(component: MediumComponent) {
titleFlow = component.title,
isFavoriteFlow = component.isFavorite,
isFavoriteBlockedFlow = component.isFavoriteBlocked,
siteUrlFlow = component.siteUrl,
showShare = listState.isScrollingUp(),
onBack = { component.back() },
onToggleFavorite = { component.toggleFavorite() }
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,16 @@ class MediumScreenComponent(
initialValue = initialMedium.isFavoriteBlocked
)

override val siteUrl: StateFlow<String> = mediumSuccessState.mapNotNull {
it?.data?.siteUrl
}.flowOn(
context = ioDispatcher()
).stateIn(
scope = ioScope(),
started = SharingStarted.WhileSubscribed(),
initialValue = initialMedium.siteUrl
)

private val burningSeriesResolver by di.instance<BurningSeriesResolver>()

override val bsAvailable: Boolean
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
package dev.datlag.aniflow.ui.navigation.screen.medium.component

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateContentSize
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBackIosNew
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.icons.filled.FavoriteBorder
import androidx.compose.material.icons.filled.Share
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
Expand All @@ -21,6 +20,7 @@ import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shadow
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import coil3.compose.AsyncImage
Expand All @@ -33,6 +33,9 @@ import dev.datlag.aniflow.anilist.MediumStateMachine
import dev.datlag.aniflow.anilist.model.Medium
import dev.datlag.aniflow.common.notPreferred
import dev.datlag.aniflow.common.preferred
import dev.datlag.aniflow.ui.custom.shareHandler
import dev.datlag.tooling.compose.ifFalse
import dev.datlag.tooling.compose.ifTrue
import dev.datlag.tooling.decompose.lifecycle.collectAsStateWithLifecycle
import kotlinx.coroutines.flow.StateFlow
import kotlin.math.max
Expand All @@ -49,6 +52,8 @@ fun CollapsingToolbar(
titleFlow: StateFlow<Medium.Title>,
isFavoriteFlow: StateFlow<Boolean>,
isFavoriteBlockedFlow: StateFlow<Boolean>,
siteUrlFlow: StateFlow<String>,
showShare: Boolean,
onBack: () -> Unit,
onToggleFavorite: () -> Unit
) {
Expand Down Expand Up @@ -146,37 +151,60 @@ fun CollapsingToolbar(
}
},
actions = {
val mediumState by mediumStateFlow.collectAsStateWithLifecycle()

AnimatedVisibility(
visible = mediumState.isSuccess,
enter = fadeIn(),
exit = fadeOut()
Row(
modifier = Modifier
.animateContentSize()
.ifFalse(isCollapsed) {
background(MaterialTheme.colorScheme.surface.copy(alpha = 0.75F), CircleShape)
},
horizontalArrangement = Arrangement.End,
verticalAlignment = Alignment.CenterVertically,
) {
val isFavoriteBlocked by isFavoriteBlockedFlow.collectAsStateWithLifecycle()
val isFavorite by isFavoriteFlow.collectAsStateWithLifecycle()
var favoriteChanged by remember(isFavorite) { mutableStateOf<Boolean?>(null) }
val mediumState by mediumStateFlow.collectAsStateWithLifecycle()
val siteUrl by siteUrlFlow.collectAsStateWithLifecycle()
val shareHandler = shareHandler()

IconButton(
modifier = if (isCollapsed) {
Modifier
} else {
Modifier.background(MaterialTheme.colorScheme.surface.copy(alpha = 0.75F), CircleShape)
},
onClick = {
favoriteChanged = !(favoriteChanged ?: isFavorite)
onToggleFavorite()
},
enabled = !isFavoriteBlocked
AnimatedVisibility(
visible = mediumState.isSuccess,
enter = fadeIn(),
exit = fadeOut()
) {
Icon(
imageVector = if (favoriteChanged ?: isFavorite) {
Icons.Default.Favorite
} else {
Icons.Default.FavoriteBorder
val isFavoriteBlocked by isFavoriteBlockedFlow.collectAsStateWithLifecycle()
val isFavorite by isFavoriteFlow.collectAsStateWithLifecycle()
var favoriteChanged by remember(isFavorite) { mutableStateOf<Boolean?>(null) }

IconButton(
onClick = {
favoriteChanged = !(favoriteChanged ?: isFavorite)
onToggleFavorite()
},
contentDescription = null
)
enabled = !isFavoriteBlocked
) {
Icon(
imageVector = if (favoriteChanged ?: isFavorite) {
Icons.Default.Favorite
} else {
Icons.Default.FavoriteBorder
},
contentDescription = null
)
}
}
AnimatedVisibility(
visible = showShare,
enter = fadeIn(),
exit = fadeOut()
) {
IconButton(
onClick = {
shareHandler.share(siteUrl)
}
) {
Icon(
imageVector = Icons.Default.Share,
contentDescription = null
)
}
}
}
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package dev.datlag.aniflow.ui.custom

import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.platform.UriHandler

@Composable
actual fun shareHandler(): ShareHandler {
val uriHandler = LocalUriHandler.current
return remember(uriHandler) {
ShareHandler(uriHandler)
}
}

actual class ShareHandler(
private val uriHandler: UriHandler
) {
actual fun share(url: String?) {
if (!url.isNullOrBlank()) {
uriHandler.openUri(url)
}
}
}

0 comments on commit a4f1190

Please sign in to comment.