add external ids (socials) to movies, tv, and people views

This commit is contained in:
Owen LeJeune
2023-06-14 15:59:06 -04:00
parent 76083761a9
commit 76cfd18bb5
35 changed files with 239 additions and 168 deletions

View File

@@ -25,4 +25,6 @@ interface DetailService {
suspend fun getWatchProviders(id: Int): Response<WatchProviderResponse>
suspend fun getExternalIds(id: Int): Response<ExternalIds>
}

View File

@@ -58,4 +58,7 @@ interface MoviesApi {
@GET("movie/{id}/watch/providers")
suspend fun getWatchProviders(@Path("id") id: Int): Response<WatchProviderResponse>
@GET("movie/{id}/external_ids")
suspend fun getExternalIds(@Path("id") id: Int): Response<ExternalIds>
}

View File

@@ -3,6 +3,7 @@ package com.owenlejeune.tvtime.api.tmdb.api.v3
import com.owenlejeune.tvtime.api.tmdb.TmdbClient
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.CastAndCrew
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.DetailedItem
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.ExternalIds
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.HomePageResponse
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.ImageCollection
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.KeywordsResponse
@@ -82,4 +83,8 @@ class MoviesService: KoinComponent, DetailService, HomePageService {
return movieService.getWatchProviders(id)
}
override suspend fun getExternalIds(id: Int): Response<ExternalIds> {
return movieService.getExternalIds(id)
}
}

View File

@@ -1,6 +1,7 @@
package com.owenlejeune.tvtime.api.tmdb.api.v3
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.DetailPerson
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.ExternalIds
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.HomePagePeopleResponse
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.PersonCreditsResponse
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.PersonImageCollection
@@ -32,4 +33,7 @@ interface PeopleApi {
// @GET("persons/{id}/tagged_images")
// suspend fun getTaggedImages(@Path("id") id: Int, @Query("page") page: Int = 1): Response<PersonImageCollection>
@GET("person/{id}/external_ids")
suspend fun getExternalIds(@Path("id") id: Int): Response<ExternalIds>
}

View File

@@ -2,6 +2,7 @@ package com.owenlejeune.tvtime.api.tmdb.api.v3
import com.owenlejeune.tvtime.api.tmdb.TmdbClient
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.DetailPerson
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.ExternalIds
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.HomePagePeopleResponse
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.PersonCreditsResponse
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.PersonImageCollection
@@ -28,4 +29,8 @@ class PeopleService: KoinComponent {
return service.getPopular(page)
}
suspend fun getExternalIds(id: Int): Response<ExternalIds> {
return service.getExternalIds(id)
}
}

View File

@@ -61,4 +61,7 @@ interface TvApi {
@GET("tv/{id}/watch/providers")
suspend fun getWatchProviders(@Path("id") seriesId: Int): Response<WatchProviderResponse>
@GET("tv/{id}/external_ids")
suspend fun getExternalIds(@Path("id") id: Int): Response<ExternalIds>
}

View File

@@ -3,6 +3,7 @@ package com.owenlejeune.tvtime.api.tmdb.api.v3
import com.owenlejeune.tvtime.api.tmdb.TmdbClient
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.CastAndCrew
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.DetailedItem
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.ExternalIds
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.HomePageResponse
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.ImageCollection
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.KeywordsResponse
@@ -87,4 +88,8 @@ class TvService: KoinComponent, DetailService, HomePageService {
return service.getSeason(seriesId, seasonId)
}
override suspend fun getExternalIds(id: Int): Response<ExternalIds> {
return service.getExternalIds(id)
}
}

View File

@@ -0,0 +1,22 @@
package com.owenlejeune.tvtime.api.tmdb.api.v3.model
import com.google.gson.annotations.SerializedName
data class ExternalIds(
@SerializedName("facebook_id")
val facebook: String?,
@SerializedName("instagram_id")
val instagram: String?,
@SerializedName("tiktok_id")
val tiktok: String?,
@SerializedName("twitter_id")
val twitter: String?,
@SerializedName("youtube_id")
val youtube: String?
) {
fun hasExternalIds(): Boolean = (facebook != null)
.or(instagram != null)
.or(tiktok != null)
.or(twitter != null)
.or(youtube != null)
}

View File

@@ -1,18 +1,26 @@
package com.owenlejeune.tvtime.ui.components
import android.content.Intent
import android.net.Uri
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@@ -24,6 +32,7 @@ import com.google.accompanist.pager.HorizontalPager
import com.google.accompanist.pager.PagerState
import com.google.accompanist.pager.rememberPagerState
import com.owenlejeune.tvtime.R
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.ExternalIds
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.ImageCollection
import com.owenlejeune.tvtime.ui.viewmodel.ConfigurationViewModel
import com.owenlejeune.tvtime.utils.TmdbUtils
@@ -220,4 +229,56 @@ fun RatingView(
size = 50.dp
)
}
}
@Composable
fun ExternalIdsArea(
externalIds: ExternalIds,
modifier: Modifier = Modifier
) {
if (externalIds.hasExternalIds()) {
Row(
modifier = modifier,
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
externalIds.twitter?.let {
ExternalIdLogo(url = "https://twitter.com/$it", logoPainter = painterResource(id = R.drawable.twitter_logo))
}
externalIds.facebook?.let {
ExternalIdLogo(url = "https://facebook.com/$it", logoPainter = painterResource(id = R.drawable.facebook_logo))
}
externalIds.instagram?.let {
ExternalIdLogo(url = "https://instagram.com/$it", logoPainter = painterResource(id = R.drawable.instagram_logo))
}
externalIds.tiktok?.let {
ExternalIdLogo(url = "https://tiktok.com/@$it", logoPainter = painterResource(id = R.drawable.tiktok_logo))
}
externalIds.youtube?.let {
ExternalIdLogo(url = "https://youtube.com/$it", logoPainter = painterResource(id = R.drawable.youtube_logo))
}
}
}
}
@Composable
private fun ExternalIdLogo(
logoPainter: Painter,
url: String,
) {
val context = LocalContext.current
IconButton(
onClick = {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
context.startActivity(intent)
},
modifier = Modifier.size(28.dp)
) {
Icon(
painter = logoPainter,
contentDescription = null,
tint = MaterialTheme.colorScheme.secondary
)
}
}

View File

@@ -619,40 +619,6 @@ fun HtmlText(text: String, modifier: Modifier = Modifier, color: Color = Color.U
)
}
@Composable
fun CircleBackgroundColorImage(
size: Dp,
backgroundColor: Color,
painter: Painter,
modifier: Modifier = Modifier,
imageSize: DpSize? = null,
imageAlignment: Alignment = Alignment.Center,
contentDescription: String? = null,
colorFilter: ColorFilter? = null
) {
Box(
modifier = modifier
.clip(CircleShape)
.size(size)
.background(color = backgroundColor)
) {
val mod = if (imageSize != null) {
Modifier
.align(imageAlignment)
.size(size = imageSize)
} else {
Modifier.align(imageAlignment)
}
Image(
contentDescription = contentDescription,
modifier = mod,
colorFilter = colorFilter,
painter = painter,
contentScale = ContentScale.FillBounds
)
}
}
@Composable
fun CircleBackgroundColorImage(
size: Dp,
@@ -1090,7 +1056,7 @@ fun SearchBar(
placeHolder = stringResource(id = R.string.search_placeholder, placeholder),
leadingIcon = {
Image(
painter = painterResource(id = R.drawable.ic_search),
imageVector = Icons.Filled.Search,
contentDescription = stringResource(R.string.search_icon_content_descriptor),
colorFilter = ColorFilter.tint(color = MaterialTheme.colorScheme.primary)
)

View File

@@ -1,9 +1,15 @@
package com.owenlejeune.tvtime.ui.navigation
import androidx.compose.foundation.layout.RowScope
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Face
import androidx.compose.material.icons.outlined.Movie
import androidx.compose.material.icons.outlined.Person
import androidx.compose.material.icons.outlined.Tv
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
@@ -62,7 +68,7 @@ fun HomeScreenNavHost(
sealed class HomeScreenNavItem(
stringRes: Int,
val icon: Int,
val icon: ImageVector,
val route: String,
private val orderGetter: (AppPreferences) -> Int,
private val orderSetter: (AppPreferences, Int) -> Unit
@@ -97,21 +103,21 @@ sealed class HomeScreenNavItem(
object Movies: HomeScreenNavItem(
R.string.nav_movies_title,
R.drawable.ic_movie,
Icons.Outlined.Movie,
"movies_route",
{ it.moviesTabPosition },
{ p, i -> p.moviesTabPosition = i }
)
object TV: HomeScreenNavItem(
R.string.nav_tv_title,
R.drawable.ic_tv,
Icons.Outlined.Tv,
"tv_route",
{ it.tvTabPosition },
{ p, i -> p.tvTabPosition = i }
)
object Account: HomeScreenNavItem(
R.string.nav_account_title,
R.drawable.ic_person,
Icons.Outlined.Person,
"account_route",
{
// if (SessionManager.currentSession.value?.isAuthorized == true) {
@@ -124,7 +130,7 @@ sealed class HomeScreenNavItem(
)
object People: HomeScreenNavItem(
R.string.nav_people_title,
R.drawable.ic_face,
Icons.Outlined.Face,
"people_route",
{ it.peopleTabPosition },
{ p, i -> p.peopleTabPosition = i }

View File

@@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.NavigationRailDefaults
import androidx.compose.material.Scaffold
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
@@ -19,8 +20,10 @@ import androidx.compose.material3.LargeTopAppBar
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.NavigationBarItemDefaults
import androidx.compose.material3.NavigationRail
import androidx.compose.material3.NavigationRailItem
import androidx.compose.material3.NavigationRailItemDefaults
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior
@@ -35,7 +38,6 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.compositeOver
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import androidx.navigation.NavHostController
@@ -161,7 +163,7 @@ private fun BottomNavBar(
modifier = Modifier
.padding(4.dp)
.clip(RoundedCornerShape(24.dp)),
icon = { Icon(painter = painterResource(id = item.icon), contentDescription = null) },
icon = { Icon(imageVector = item.icon, contentDescription = null) },
label = {
val name = if (preferences.showBottomTabLabels) item.name else " "
Text(text = name)
@@ -171,7 +173,11 @@ private fun BottomNavBar(
if (!isSelected) {
navController.navigateInBottomBar(item.route)
}
}
},
colors = NavigationBarItemDefaults.colors(
indicatorColor = MaterialTheme.colorScheme.secondary,
selectedIconColor = MaterialTheme.colorScheme.onSecondary
)
)
}
}
@@ -252,14 +258,15 @@ private fun DualColumnMainContent(
HomeScreenNavItem.SortedItems.forEachIndexed { index, item ->
val isSelected = currentRoute == item.route
NavigationRailItem(
icon = { Icon(painter = painterResource(id = item.icon), contentDescription = null) },
icon = { Icon(imageVector = item.icon, contentDescription = null) },
label = { if (preferences.showBottomTabLabels) Text(item.name) },
selected = isSelected,
onClick = {
if (!isSelected) {
navController.navigateInBottomBar(item.route)
}
}
},
colors = NavigationRailItemDefaults.colors(indicatorColor = MaterialTheme.colorScheme.secondary)
)
if (index < HomeScreenNavItem.SortedItems.size - 1) {
Spacer(modifier = Modifier.height(20.dp))

View File

@@ -12,7 +12,11 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.Book
import androidx.compose.material.icons.filled.Bookmark
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.icons.filled.Star
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
@@ -573,7 +577,7 @@ private fun ActionButtonRow(listItem: ListItem) {
ActionButton(
itemId = listItem.id,
type = listItem.mediaType,
iconRes = R.drawable.ic_favorite,
imageVector = Icons.Filled.Favorite,
contentDescription = stringResource(id = R.string.favourite_label),
isSelected = isFavourited,
filledIconColor = FavoriteSelected,
@@ -583,7 +587,7 @@ private fun ActionButtonRow(listItem: ListItem) {
ActionButton(
itemId = listItem.id,
type = listItem.mediaType,
iconRes = R.drawable.ic_watchlist,
imageVector = Icons.Filled.Bookmark,
contentDescription = "",
isSelected = isWatchlisted,
filledIconColor = WatchlistSelected,
@@ -594,7 +598,7 @@ private fun ActionButtonRow(listItem: ListItem) {
ActionButton(
itemId = listItem.id,
type = listItem.mediaType,
iconRes = R.drawable.ic_rating_star,
imageVector = Icons.Filled.Star,
contentDescription = "",
isSelected = isRated,
filledIconColor = RatingSelected,

View File

@@ -20,6 +20,10 @@ import androidx.compose.material.icons.filled.Send
import androidx.compose.material.icons.outlined.ExpandMore
import androidx.compose.material3.*
import androidx.compose.material.TabRow
import androidx.compose.material.icons.filled.Bookmark
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.icons.filled.List
import androidx.compose.material.icons.filled.Star
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -27,6 +31,7 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
@@ -188,6 +193,8 @@ private fun MediaViewContent(
showImageGallery: MutableState<Boolean>,
pagerState: PagerState
) {
val scope = rememberCoroutineScope()
Row(
modifier = Modifier
.background(color = MaterialTheme.colorScheme.background),
@@ -219,6 +226,22 @@ private fun MediaViewContent(
MiscTvDetails(mediaItem = mediaItem, service as TvService)
}
val externalIds = remember { mutableStateOf<ExternalIds?>(null) }
LaunchedEffect(Unit) {
scope.launch {
val response = service.getExternalIds(itemId!!)
if (response.isSuccessful) {
externalIds.value = response.body()!!
}
}
}
externalIds.value?.let {
ExternalIdsArea(
externalIds = it,
modifier = Modifier.padding(start = 20.dp)
)
}
ActionsView(itemId = itemId, type = type, service = service)
if (type == MediaViewType.MOVIE) {
@@ -587,7 +610,7 @@ fun ActionButton(
modifier: Modifier = Modifier,
itemId: Int,
type: MediaViewType,
iconRes: Int,
imageVector: ImageVector,
contentDescription: String,
isSelected: Boolean,
filledIconColor: Color,
@@ -628,7 +651,7 @@ fun ActionButton(
modifier = Modifier
.clip(CircleShape)
.align(Alignment.Center),
painter = painterResource(id = iconRes),
imageVector = imageVector,
contentDescription = contentDescription,
tint = tintColor.value
)
@@ -685,7 +708,7 @@ private fun RateButton(
modifier = Modifier
.clip(CircleShape)
.align(Alignment.Center),
painter = painterResource(id = R.drawable.ic_rating_star),
imageVector = Icons.Filled.Star,
contentDescription = "",
tint = tintColor.value
)
@@ -727,7 +750,7 @@ fun WatchlistButton(
modifier = modifier,
itemId = itemId,
type = type,
iconRes = R.drawable.ic_watchlist,
imageVector = Icons.Filled.Bookmark,
contentDescription = "",
isSelected = hasWatchlistedItem,
filledIconColor = WatchlistSelected,
@@ -760,7 +783,7 @@ fun ListButton(
),
size = 40.dp,
backgroundColor = MaterialTheme.colorScheme.actionButtonColor,
painter = painterResource(id = R.drawable.ic_add_to_list),
image = Icons.Filled.List,
colorFilter = ColorFilter.tint(color = /*if (hasWatchlistedItem.value) WatchlistSelected else*/ MaterialTheme.colorScheme.background),
contentDescription = ""
)
@@ -786,7 +809,7 @@ fun FavoriteButton(
modifier = modifier,
itemId = itemId,
type = type,
iconRes = R.drawable.ic_favorite,
imageVector = Icons.Filled.Favorite,
contentDescription = "",
isSelected = isFavourited,
filledIconColor = FavoriteSelected,

View File

@@ -10,9 +10,11 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
@@ -24,10 +26,12 @@ import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.owenlejeune.tvtime.R
import com.owenlejeune.tvtime.api.tmdb.api.v3.PeopleService
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.DetailPerson
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.ExternalIds
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.PersonCreditsResponse
import com.owenlejeune.tvtime.ui.components.ContentCard
import com.owenlejeune.tvtime.ui.components.DetailHeader
import com.owenlejeune.tvtime.ui.components.ExpandableContentCard
import com.owenlejeune.tvtime.ui.components.ExternalIdsArea
import com.owenlejeune.tvtime.ui.components.TwoLineImageTextCard
import com.owenlejeune.tvtime.ui.navigation.AppNavItem
import com.owenlejeune.tvtime.utils.TmdbUtils
@@ -83,6 +87,8 @@ fun PersonDetailScreen(
)
}
) { innerPadding ->
val scope = rememberCoroutineScope()
Box(modifier = Modifier.padding(innerPadding)) {
Column(
modifier = Modifier
@@ -98,6 +104,22 @@ fun PersonDetailScreen(
BiographyCard(person = person.value)
val externalIds = remember { mutableStateOf<ExternalIds?>(null) }
LaunchedEffect(Unit) {
scope.launch {
val response = PeopleService().getExternalIds(personId!!)
if (response.isSuccessful) {
externalIds.value = response.body()!!
}
}
}
externalIds.value?.let {
ExternalIdsArea(
externalIds = it,
modifier = Modifier.padding(start = 4.dp)
)
}
val credits = remember { mutableStateOf<PersonCreditsResponse?>(null) }
personId?.let {
if (credits.value == null) {

View File

@@ -4,15 +4,12 @@ import android.os.Build
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Brightness6

View File

@@ -13,7 +13,6 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.recyclerview.widget.RecyclerView
@@ -75,7 +74,7 @@ class HomeTabRecyclerAdapter: RecyclerView.Adapter<HomeTabRecyclerAdapter.TabVie
) {
Icon(
modifier = Modifier.size(24.dp),
painter = painterResource(id = page.icon),
imageVector = page.icon,
contentDescription = page.name
)
Text(

View File

@@ -16,7 +16,7 @@ object FileUtils {
// char in that case. So we make it 4K to cover most, if not all, cases...
val buffer = ByteArray(4096)
val sb = java.lang.StringBuilder()
var bytesRead = 0
var bytesRead: Int
while (bis.read(buffer).also { bytesRead = it } > 0) {
val text = String(buffer, 0, bytesRead)
sb.append(text)

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="50dp"
android:height="50dp"
android:viewportWidth="50"
android:viewportHeight="50">
<path
android:fillColor="#FF000000"
android:pathData="M25,3C12.85,3 3,12.85 3,25c0,11.03 8.125,20.137 18.712,21.728V30.831h-5.443v-5.783h5.443v-3.848c0,-6.371 3.104,-9.168 8.399,-9.168c2.536,0 3.877,0.188 4.512,0.274v5.048h-3.612c-2.248,0 -3.033,2.131 -3.033,4.533v3.161h6.588l-0.894,5.783h-5.694v15.944C38.716,45.318 47,36.137 47,25C47,12.85 37.15,3 25,3z"/>
</vector>

View File

@@ -1,11 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal"
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
android:pathData="M4,10.5c-0.83,0 -1.5,0.67 -1.5,1.5s0.67,1.5 1.5,1.5 1.5,-0.67 1.5,-1.5 -0.67,-1.5 -1.5,-1.5zM4,4.5c-0.83,0 -1.5,0.67 -1.5,1.5S3.17,7.5 4,7.5 5.5,6.83 5.5,6 4.83,4.5 4,4.5zM4,16.5c-0.83,0 -1.5,0.68 -1.5,1.5s0.68,1.5 1.5,1.5 1.5,-0.68 1.5,-1.5 -0.67,-1.5 -1.5,-1.5zM7,19h14v-2L7,17v2zM7,13h14v-2L7,11v2zM7,5v2h14L21,5L7,5z"/>
</vector>

View File

@@ -1,11 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal"
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
</vector>

View File

@@ -1,5 +0,0 @@
<vector android:height="24dp" android:tint="@android:color/darker_gray"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M21,5v6.59l-3,-3.01 -4,4.01 -4,-4 -4,4 -3,-3.01L3,5c0,-1.1 0.9,-2 2,-2h14c1.1,0 2,0.9 2,2zM18,11.42l3,3.01L21,19c0,1.1 -0.9,2 -2,2L5,21c-1.1,0 -2,-0.9 -2,-2v-6.58l3,2.99 4,-4 4,4 4,-3.99z"/>
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M9,11.75c-0.69,0 -1.25,0.56 -1.25,1.25s0.56,1.25 1.25,1.25 1.25,-0.56 1.25,-1.25 -0.56,-1.25 -1.25,-1.25zM15,11.75c-0.69,0 -1.25,0.56 -1.25,1.25s0.56,1.25 1.25,1.25 1.25,-0.56 1.25,-1.25 -0.56,-1.25 -1.25,-1.25zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8 0,-0.29 0.02,-0.58 0.05,-0.86 2.36,-1.05 4.23,-2.98 5.21,-5.37C11.07,8.33 14.05,10 17.42,10c0.78,0 1.53,-0.09 2.25,-0.26 0.21,0.71 0.33,1.47 0.33,2.26 0,4.41 -3.59,8 -8,8z"/>
</vector>

View File

@@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M12,21.35l-1.45,-1.32C5.4,15.36 2,12.28 2,8.5 2,5.42 4.42,3 7.5,3c1.74,0 3.41,0.81 4.5,2.09C13.09,3.81 14.76,3 16.5,3 19.58,3 22,5.42 22,8.5c0,3.78 -3.4,6.86 -8.55,11.54L12,21.35z"/>
</vector>

View File

@@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M18,4l2,4h-3l-2,-4h-2l2,4h-3l-2,-4H8l2,4H7L5,4H4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V4h-4z"/>
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M12,17.27L18.18,21l-1.64,-7.03L22,9.24l-7.19,-0.61L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21z"/>
</vector>

View File

@@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94c0,-0.32 -0.02,-0.64 -0.07,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.36 4.8,11.69 4.8,12s0.02,0.64 0.07,0.94l-2.03,1.58c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z"/>
</vector>

View File

@@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h5v2h8v-2h5c1.1,0 1.99,-0.9 1.99,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM21,17L3,17L3,5h18v12z"/>
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M17,3H7c-1.1,0 -1.99,0.9 -1.99,2L5,21l7,-3 7,3V5c0,-1.1 -0.9,-2 -2,-2z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="50dp"
android:height="50dp"
android:viewportWidth="50"
android:viewportHeight="50">
<path
android:fillColor="#FF000000"
android:pathData="M16,3C8.83,3 3,8.83 3,16L3,34C3,41.17 8.83,47 16,47L34,47C41.17,47 47,41.17 47,34L47,16C47,8.83 41.17,3 34,3L16,3zM37,11C38.1,11 39,11.9 39,13C39,14.1 38.1,15 37,15C35.9,15 35,14.1 35,13C35,11.9 35.9,11 37,11zM25,14C31.07,14 36,18.93 36,25C36,31.07 31.07,36 25,36C18.93,36 14,31.07 14,25C14,18.93 18.93,14 25,14zM25,16C20.04,16 16,20.04 16,25C16,29.96 20.04,34 25,34C29.96,34 34,29.96 34,25C34,20.04 29.96,16 25,16z"/>
</vector>

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/placeholder"/>
<item android:drawable="@drawable/ic_person" android:gravity="center"/>
</layer-list>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="50dp"
android:height="50dp"
android:viewportWidth="50"
android:viewportHeight="50">
<path
android:fillColor="#FF000000"
android:pathData="M41,4H9C6.243,4 4,6.243 4,9v32c0,2.757 2.243,5 5,5h32c2.757,0 5,-2.243 5,-5V9C46,6.243 43.757,4 41,4zM37.006,22.323c-0.227,0.021 -0.457,0.035 -0.69,0.035c-2.623,0 -4.928,-1.349 -6.269,-3.388c0,5.349 0,11.435 0,11.537c0,4.709 -3.818,8.527 -8.527,8.527s-8.527,-3.818 -8.527,-8.527s3.818,-8.527 8.527,-8.527c0.178,0 0.352,0.016 0.527,0.027v4.202c-0.175,-0.021 -0.347,-0.053 -0.527,-0.053c-2.404,0 -4.352,1.948 -4.352,4.352s1.948,4.352 4.352,4.352s4.527,-1.894 4.527,-4.298c0,-0.095 0.042,-19.594 0.042,-19.594h4.016c0.378,3.591 3.277,6.425 6.901,6.685V22.323z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="50dp"
android:height="50dp"
android:viewportWidth="50"
android:viewportHeight="50">
<path
android:fillColor="#FF000000"
android:pathData="M50.063,10.438C48.215,11.258 46.234,11.809 44.152,12.059C46.277,10.785 47.91,8.77 48.676,6.371C46.691,7.547 44.484,8.402 42.145,8.863C40.27,6.863 37.598,5.617 34.641,5.617C28.961,5.617 24.355,10.219 24.355,15.898C24.355,16.703 24.449,17.488 24.625,18.242C16.078,17.813 8.504,13.719 3.43,7.496C2.543,9.02 2.039,10.785 2.039,12.668C2.039,16.234 3.852,19.383 6.613,21.23C4.926,21.176 3.34,20.711 1.953,19.941C1.953,19.984 1.953,20.027 1.953,20.07C1.953,25.055 5.5,29.207 10.199,30.156C9.34,30.391 8.43,30.516 7.492,30.516C6.828,30.516 6.184,30.453 5.555,30.328C6.867,34.41 10.664,37.391 15.16,37.473C11.645,40.23 7.211,41.871 2.391,41.871C1.559,41.871 0.742,41.824 -0.059,41.727C4.488,44.648 9.895,46.348 15.703,46.348C34.617,46.348 44.961,30.68 44.961,17.094C44.961,16.648 44.949,16.199 44.934,15.762C46.941,14.313 48.684,12.5 50.063,10.438Z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="50dp"
android:height="50dp"
android:viewportWidth="50"
android:viewportHeight="50">
<path
android:fillColor="#FF000000"
android:pathData="M44.898,14.5C44.5,12.301 42.602,10.699 40.398,10.199C37.102,9.5 31,9 24.398,9C17.801,9 11.602,9.5 8.301,10.199C6.102,10.699 4.199,12.199 3.801,14.5C3.398,17 3,20.5 3,25C3,29.5 3.398,33 3.898,35.5C4.301,37.699 6.199,39.301 8.398,39.801C11.898,40.5 17.898,41 24.5,41C31.102,41 37.102,40.5 40.602,39.801C42.801,39.301 44.699,37.801 45.102,35.5C45.5,33 46,29.398 46.102,25C45.898,20.5 45.398,17 44.898,14.5ZM19,32L19,18L31.199,25Z"/>
</vector>