From 6977a525fe8e81cb345a182dddaa440ea44f621b Mon Sep 17 00:00:00 2001 From: Suhas Dissanayake Date: Sun, 13 Aug 2023 23:19:34 +0530 Subject: [PATCH 1/4] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 55805ab..1c17005 100644 --- a/README.md +++ b/README.md @@ -42,3 +42,6 @@ [Get it on GitHub](https://github.com/SuhasDissa/MemerizeApp/releases/latest) + +## Translations +[Crowdin Translate](https://crowdin.com/project/memerize) From cd425ffc2ecd6553a111cfdd3227c09823a6c23a Mon Sep 17 00:00:00 2001 From: Suhas Dissanayake Date: Mon, 14 Aug 2023 14:19:44 +0530 Subject: [PATCH 2/4] Add more sort options --- .../memerize/backend/apis/LemmyApi.kt | 4 +- .../memerize/backend/apis/RedditApi.kt | 5 +- .../suhasdissa/memerize/backend/model/Sort.kt | 32 +++++++++ .../memerize/backend/model/SortTime.kt | 28 -------- .../repositories/LemmyMemeRepository.kt | 5 +- .../backend/repositories/MemeRepository.kt | 3 +- .../repositories/RedditMemeRepository.kt | 19 +++-- .../backend/viewmodels/LemmyViewModel.kt | 11 ++- .../backend/viewmodels/RedditViewModel.kt | 13 ++-- .../memerize/ui/components/SortBottomSheet.kt | 70 +++++++++++++++++++ .../memerize/ui/screens/home/HomeScreen.kt | 3 +- .../ui/screens/primary/LemmyMemeScreen.kt | 53 ++------------ .../ui/screens/primary/RedditMemeScreen.kt | 48 ++----------- app/src/main/res/values/strings.xml | 5 ++ 14 files changed, 159 insertions(+), 140 deletions(-) create mode 100644 app/src/main/java/app/suhasdissa/memerize/backend/model/Sort.kt delete mode 100644 app/src/main/java/app/suhasdissa/memerize/backend/model/SortTime.kt create mode 100644 app/src/main/java/app/suhasdissa/memerize/ui/components/SortBottomSheet.kt diff --git a/app/src/main/java/app/suhasdissa/memerize/backend/apis/LemmyApi.kt b/app/src/main/java/app/suhasdissa/memerize/backend/apis/LemmyApi.kt index 510cb2b..4090c1c 100644 --- a/app/src/main/java/app/suhasdissa/memerize/backend/apis/LemmyApi.kt +++ b/app/src/main/java/app/suhasdissa/memerize/backend/apis/LemmyApi.kt @@ -20,7 +20,9 @@ private const val header = interface LemmyApi { /** * @param community The name of the community. - * @param sort "TopAll", "TopDay", "TopMonth", "TopWeek". + * @param sort "Active", "Hot", "MostComments", "New", "NewComments", + * "Old", "TopAll", "TopDay", "TopMonth", "TopWeek", + * "TopYear". */ @Headers(header) @GET("https://{instance}/api/v3/post/list") diff --git a/app/src/main/java/app/suhasdissa/memerize/backend/apis/RedditApi.kt b/app/src/main/java/app/suhasdissa/memerize/backend/apis/RedditApi.kt index 84e3ad9..0f73222 100644 --- a/app/src/main/java/app/suhasdissa/memerize/backend/apis/RedditApi.kt +++ b/app/src/main/java/app/suhasdissa/memerize/backend/apis/RedditApi.kt @@ -19,10 +19,11 @@ private const val header = interface RedditApi { @Headers(header) - @GET("r/{subreddit}/top.json?sort=top&limit=100") + @GET("r/{subreddit}/{sort}.json") suspend fun getRedditData( @Path("subreddit") subreddit: String, - @Query("t") time: String + @Path("sort") sort: String, + @Query("t") time: String? = null ): Reddit @Headers(header) diff --git a/app/src/main/java/app/suhasdissa/memerize/backend/model/Sort.kt b/app/src/main/java/app/suhasdissa/memerize/backend/model/Sort.kt new file mode 100644 index 0000000..cd57337 --- /dev/null +++ b/app/src/main/java/app/suhasdissa/memerize/backend/model/Sort.kt @@ -0,0 +1,32 @@ +/******************************************************************************* +Created By Suhas Dissanayake on 7/30/23, 6:12 PM +Copyright (c) 2023 +https://github.com/SuhasDissa/ +All Rights Reserved + ******************************************************************************/ + +package app.suhasdissa.memerize.backend.model + +import app.suhasdissa.memerize.R + +sealed class Sort(open val name: Int, val redditSort: String, open val lemmySort: String) { + object Hot : Sort(R.string.hot, "hot", "Hot") + object New : Sort(R.string.sort_new, "new", "New") + object Rising : Sort(R.string.rising, "rising", "Active") + sealed class Top(val redditT: String) : Sort(R.string.top, "top", "") { + object Today : Top("today") { + override val name = R.string.reddit_today_btn + override val lemmySort = "TopDay" + } + + object Week : Top("week") { + override val name = R.string.reddit_week_btn + override val lemmySort = "TopWeek" + } + + object Month : Top("month") { + override val name = R.string.reddit_month_btn + override val lemmySort = "TopMonth" + } + } +} diff --git a/app/src/main/java/app/suhasdissa/memerize/backend/model/SortTime.kt b/app/src/main/java/app/suhasdissa/memerize/backend/model/SortTime.kt deleted file mode 100644 index 4f5117e..0000000 --- a/app/src/main/java/app/suhasdissa/memerize/backend/model/SortTime.kt +++ /dev/null @@ -1,28 +0,0 @@ -/******************************************************************************* -Created By Suhas Dissanayake on 7/30/23, 6:12 PM -Copyright (c) 2023 -https://github.com/SuhasDissa/ -All Rights Reserved - ******************************************************************************/ - -package app.suhasdissa.memerize.backend.model - -enum class SortTime { - TODAY, - WEEK, - MONTH -} - -val SortTime.reddit: String - get() = when (this) { - SortTime.TODAY -> "today" - SortTime.WEEK -> "week" - SortTime.MONTH -> "month" - } - -val SortTime.lemmy: String - get() = when (this) { - SortTime.TODAY -> "TopDay" - SortTime.WEEK -> "TopWeek" - SortTime.MONTH -> "TopMonth" - } diff --git a/app/src/main/java/app/suhasdissa/memerize/backend/repositories/LemmyMemeRepository.kt b/app/src/main/java/app/suhasdissa/memerize/backend/repositories/LemmyMemeRepository.kt index e9fc70d..9013243 100644 --- a/app/src/main/java/app/suhasdissa/memerize/backend/repositories/LemmyMemeRepository.kt +++ b/app/src/main/java/app/suhasdissa/memerize/backend/repositories/LemmyMemeRepository.kt @@ -13,6 +13,7 @@ import app.suhasdissa.memerize.backend.apis.LemmyApi import app.suhasdissa.memerize.backend.database.dao.LemmyMemeDAO import app.suhasdissa.memerize.backend.database.entity.LemmyCommunity import app.suhasdissa.memerize.backend.database.entity.LemmyMeme +import app.suhasdissa.memerize.backend.model.Sort interface LemmyMemeRepository : MemeRepository class LemmyMemeRepositoryImpl( @@ -22,10 +23,10 @@ class LemmyMemeRepositoryImpl( override suspend fun getOnlineData( community: LemmyCommunity, - time: String + sort: Sort ): List? { return try { - val memesList = getNetworkData(community, time) + val memesList = getNetworkData(community, sort.lemmySort) Thread { insertMemes(memesList) }.start() diff --git a/app/src/main/java/app/suhasdissa/memerize/backend/repositories/MemeRepository.kt b/app/src/main/java/app/suhasdissa/memerize/backend/repositories/MemeRepository.kt index 445a088..6f215db 100644 --- a/app/src/main/java/app/suhasdissa/memerize/backend/repositories/MemeRepository.kt +++ b/app/src/main/java/app/suhasdissa/memerize/backend/repositories/MemeRepository.kt @@ -9,8 +9,9 @@ package app.suhasdissa.memerize.backend.repositories import app.suhasdissa.memerize.backend.database.entity.AboutCommunity import app.suhasdissa.memerize.backend.database.entity.Meme +import app.suhasdissa.memerize.backend.model.Sort interface MemeRepository { - suspend fun getOnlineData(community: C, time: String): List? + suspend fun getOnlineData(community: C, sort: Sort): List? suspend fun getLocalData(community: C): List } diff --git a/app/src/main/java/app/suhasdissa/memerize/backend/repositories/RedditMemeRepository.kt b/app/src/main/java/app/suhasdissa/memerize/backend/repositories/RedditMemeRepository.kt index 4c4dbf9..b888e78 100644 --- a/app/src/main/java/app/suhasdissa/memerize/backend/repositories/RedditMemeRepository.kt +++ b/app/src/main/java/app/suhasdissa/memerize/backend/repositories/RedditMemeRepository.kt @@ -7,11 +7,13 @@ All Rights Reserved package app.suhasdissa.memerize.backend.repositories +import android.util.Log import androidx.annotation.WorkerThread import app.suhasdissa.memerize.backend.apis.RedditApi import app.suhasdissa.memerize.backend.database.dao.RedditMemeDao import app.suhasdissa.memerize.backend.database.entity.RedditCommunity import app.suhasdissa.memerize.backend.database.entity.RedditMeme +import app.suhasdissa.memerize.backend.model.Sort interface RedditMemeRepository : MemeRepository @@ -23,15 +25,20 @@ class RedditMemeRepositoryImpl( private val imageRegex = Regex("^.+\\.(jpg|jpeg|png|webp)\$") override suspend fun getOnlineData( community: RedditCommunity, - time: String + sort: Sort ): List? { + val srt = when (sort) { + is Sort.Top -> sort.redditSort to sort.redditT + else -> sort.redditSort to null + } return try { - val memesList = getNetworkData(community.id, time) + val memesList = getNetworkData(community.id, srt.first, srt.second) Thread { insertMemes(memesList) }.start() memesList } catch (e: Exception) { + Log.e("Reddit Repository", e.message, e) null } } @@ -39,9 +46,13 @@ class RedditMemeRepositoryImpl( override suspend fun getLocalData(community: RedditCommunity): List = redditMemeDao.getAll(community.id) - private suspend fun getNetworkData(subreddit: String, time: String): List { + private suspend fun getNetworkData( + subreddit: String, + sort: String, + time: String? + ): List { val memeList: ArrayList = arrayListOf() - val redditData = redditApi.getRedditData(subreddit, time).data.children + val redditData = redditApi.getRedditData(subreddit, sort, time).data.children redditData.forEach { child -> val url = child.Childdata.url if (url.matches(imageRegex)) { diff --git a/app/src/main/java/app/suhasdissa/memerize/backend/viewmodels/LemmyViewModel.kt b/app/src/main/java/app/suhasdissa/memerize/backend/viewmodels/LemmyViewModel.kt index c7c421d..c7f63ef 100644 --- a/app/src/main/java/app/suhasdissa/memerize/backend/viewmodels/LemmyViewModel.kt +++ b/app/src/main/java/app/suhasdissa/memerize/backend/viewmodels/LemmyViewModel.kt @@ -18,8 +18,7 @@ import androidx.lifecycle.viewmodel.initializer import androidx.lifecycle.viewmodel.viewModelFactory import app.suhasdissa.memerize.MemerizeApplication import app.suhasdissa.memerize.backend.database.entity.LemmyCommunity -import app.suhasdissa.memerize.backend.model.SortTime -import app.suhasdissa.memerize.backend.model.lemmy +import app.suhasdissa.memerize.backend.model.Sort import app.suhasdissa.memerize.backend.repositories.LemmyMemeRepository import app.suhasdissa.memerize.backend.viewmodels.state.MemeUiState import kotlinx.coroutines.launch @@ -31,19 +30,19 @@ class LemmyViewModel(private val lemmyRepository: LemmyMemeRepository) : var currentCommunity: LemmyCommunity? = null private set - var currentSortTime: SortTime = SortTime.TODAY + var currentSortTime: Sort = Sort.Top.Today private set fun getMemePhotos( community: LemmyCommunity? = currentCommunity, - time: SortTime = SortTime.TODAY + sort: Sort = Sort.Top.Today ) { currentCommunity = community!! - currentSortTime = time + currentSortTime = sort viewModelScope.launch { memeUiState = MemeUiState.Loading - memeUiState = when (val data = lemmyRepository.getOnlineData(community, time.lemmy)) { + memeUiState = when (val data = lemmyRepository.getOnlineData(community, sort)) { null -> { MemeUiState.Error("") } diff --git a/app/src/main/java/app/suhasdissa/memerize/backend/viewmodels/RedditViewModel.kt b/app/src/main/java/app/suhasdissa/memerize/backend/viewmodels/RedditViewModel.kt index e0934ee..956caae 100644 --- a/app/src/main/java/app/suhasdissa/memerize/backend/viewmodels/RedditViewModel.kt +++ b/app/src/main/java/app/suhasdissa/memerize/backend/viewmodels/RedditViewModel.kt @@ -19,8 +19,7 @@ import androidx.lifecycle.viewmodel.viewModelFactory import app.suhasdissa.memerize.MemerizeApplication import app.suhasdissa.memerize.backend.database.entity.RedditCommunity import app.suhasdissa.memerize.backend.database.entity.RedditMeme -import app.suhasdissa.memerize.backend.model.SortTime -import app.suhasdissa.memerize.backend.model.reddit +import app.suhasdissa.memerize.backend.model.Sort import app.suhasdissa.memerize.backend.repositories.RedditMemeRepository import app.suhasdissa.memerize.backend.viewmodels.state.MemeUiState import kotlinx.coroutines.async @@ -35,21 +34,21 @@ class RedditViewModel(private val redditRepository: RedditMemeRepository) : var currentSubreddit: RedditCommunity? = null private set - var currentSortTime: SortTime = SortTime.TODAY + var currentSortTime: Sort = Sort.Top.Today private set fun getMemePhotos( subreddit: RedditCommunity? = currentSubreddit, - time: SortTime = SortTime.TODAY + sort: Sort = Sort.Top.Today ) { currentSubreddit = subreddit!! - currentSortTime = time + currentSortTime = sort viewModelScope.launch { memeUiState = MemeUiState.Loading memeUiState = when ( val data = - redditRepository.getOnlineData(subreddit, time.reddit) + redditRepository.getOnlineData(subreddit, sort) ) { null -> { MemeUiState.Error("") @@ -76,7 +75,7 @@ class RedditViewModel(private val redditRepository: RedditMemeRepository) : currentSubreddit = null memeUiState = MemeUiState.Loading val results = communities.map { - async { redditRepository.getOnlineData(it, SortTime.TODAY.reddit) } + async { redditRepository.getOnlineData(it, Sort.Top.Today) } }.awaitAll() val memeList: List = results.filterNotNull().flatten().shuffled() memeUiState = if (memeList.isEmpty()) { diff --git a/app/src/main/java/app/suhasdissa/memerize/ui/components/SortBottomSheet.kt b/app/src/main/java/app/suhasdissa/memerize/ui/components/SortBottomSheet.kt new file mode 100644 index 0000000..44467d0 --- /dev/null +++ b/app/src/main/java/app/suhasdissa/memerize/ui/components/SortBottomSheet.kt @@ -0,0 +1,70 @@ +/******************************************************************************* +Created By Suhas Dissanayake on 8/14/23, 1:10 PM +Copyright (c) 2023 +https://github.com/SuhasDissa/ +All Rights Reserved + ******************************************************************************/ + +package app.suhasdissa.memerize.ui.components + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.FilterChip +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.ModalBottomSheet +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import app.suhasdissa.memerize.R +import app.suhasdissa.memerize.backend.model.Sort + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun SortBottomSheet(currentSort: Sort, onSelect: (Sort) -> Unit, onDismissRequest: () -> Unit) { + val options = remember { listOf(Sort.Hot, Sort.New, Sort.Rising) } + val topOptions = remember { listOf(Sort.Top.Today, Sort.Top.Week, Sort.Top.Month) } + + ModalBottomSheet(onDismissRequest) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp) + ) { + Text( + text = stringResource(R.string.sort_by), + style = MaterialTheme.typography.titleLarge + ) + Row(Modifier.fillMaxWidth(), Arrangement.SpaceEvenly) { + options.forEach { + SortFilterChip(selected = currentSort == it, sort = it, onSelect) + } + } + Text( + text = stringResource(id = R.string.top), + style = MaterialTheme.typography.titleMedium + ) + Row(Modifier.fillMaxWidth(), Arrangement.SpaceEvenly) { + topOptions.forEach { + SortFilterChip(selected = currentSort == it, sort = it, onSelect) + } + } + } + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun SortFilterChip(selected: Boolean, sort: Sort, onSelect: (Sort) -> Unit) { + FilterChip( + selected, + onClick = { onSelect(sort) }, + label = { Text(stringResource(id = sort.name)) } + ) +} diff --git a/app/src/main/java/app/suhasdissa/memerize/ui/screens/home/HomeScreen.kt b/app/src/main/java/app/suhasdissa/memerize/ui/screens/home/HomeScreen.kt index 7f947fc..213f6c1 100644 --- a/app/src/main/java/app/suhasdissa/memerize/ui/screens/home/HomeScreen.kt +++ b/app/src/main/java/app/suhasdissa/memerize/ui/screens/home/HomeScreen.kt @@ -33,7 +33,6 @@ import androidx.lifecycle.viewmodel.compose.viewModel import app.suhasdissa.memerize.Destination import app.suhasdissa.memerize.R import app.suhasdissa.memerize.backend.database.entity.RedditCommunity -import app.suhasdissa.memerize.backend.model.SortTime import app.suhasdissa.memerize.backend.viewmodels.LemmyCommunityViewModel import app.suhasdissa.memerize.backend.viewmodels.LemmyViewModel import app.suhasdissa.memerize.backend.viewmodels.RedditCommunityViewModel @@ -105,7 +104,7 @@ fun HomeScreen( selectedSubreddits.add(it) } } else { - redditViewModel.getMemePhotos(it, SortTime.TODAY) + redditViewModel.getMemePhotos(it) onNavigate(Destination.RedditMemeView) } }, diff --git a/app/src/main/java/app/suhasdissa/memerize/ui/screens/primary/LemmyMemeScreen.kt b/app/src/main/java/app/suhasdissa/memerize/ui/screens/primary/LemmyMemeScreen.kt index 0847a8c..89ed95d 100644 --- a/app/src/main/java/app/suhasdissa/memerize/ui/screens/primary/LemmyMemeScreen.kt +++ b/app/src/main/java/app/suhasdissa/memerize/ui/screens/primary/LemmyMemeScreen.kt @@ -7,24 +7,18 @@ All Rights Reserved package app.suhasdissa.memerize.ui.screens.primary -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width -import androidx.compose.foundation.lazy.grid.LazyGridState -import androidx.compose.foundation.lazy.grid.rememberLazyGridState import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.FilterList import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.FilterChip import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme @@ -44,12 +38,12 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import app.suhasdissa.memerize.R -import app.suhasdissa.memerize.backend.model.SortTime import app.suhasdissa.memerize.backend.viewmodels.LemmyViewModel import app.suhasdissa.memerize.backend.viewmodels.state.MemeUiState import app.suhasdissa.memerize.ui.components.LoadingScreen import app.suhasdissa.memerize.ui.components.MemeGrid import app.suhasdissa.memerize.ui.components.RetryScreen +import app.suhasdissa.memerize.ui.components.SortBottomSheet import coil.compose.AsyncImage import coil.request.ImageRequest @@ -102,45 +96,6 @@ fun LemmyMemeScreen( } ) { paddingValues -> Column(Modifier.padding(paddingValues)) { - val listState: LazyGridState = rememberLazyGridState() - lemmyViewModel.currentCommunity?.let { - AnimatedVisibility(visible = !listState.canScrollBackward) { - AnimatedVisibility(visible = showFilterButtons) { - Row(modifier.fillMaxWidth(), Arrangement.SpaceEvenly) { - FilterChip( - selected = lemmyViewModel.currentSortTime == SortTime.TODAY, - onClick = { - showFilterButtons = false - lemmyViewModel.getMemePhotos(time = SortTime.TODAY) - }, - label = { - Text(stringResource(R.string.reddit_today_btn)) - } - ) - FilterChip( - selected = lemmyViewModel.currentSortTime == SortTime.WEEK, - onClick = { - showFilterButtons = false - lemmyViewModel.getMemePhotos(time = SortTime.WEEK) - }, - label = { - Text(stringResource(R.string.reddit_week_btn)) - } - ) - FilterChip( - selected = lemmyViewModel.currentSortTime == SortTime.MONTH, - onClick = { - showFilterButtons = false - lemmyViewModel.getMemePhotos(time = SortTime.MONTH) - }, - label = { - Text(stringResource(R.string.reddit_month_btn)) - } - ) - } - } - } - } when (val memeDataState = lemmyViewModel.memeUiState) { is MemeUiState.Loading -> LoadingScreen(modifier) is MemeUiState.Error -> RetryScreen( @@ -158,4 +113,10 @@ fun LemmyMemeScreen( } } } + if (showFilterButtons) { + SortBottomSheet(currentSort = lemmyViewModel.currentSortTime, onSelect = { + showFilterButtons = false + lemmyViewModel.getMemePhotos(sort = it) + }, onDismissRequest = { showFilterButtons = false }) + } } diff --git a/app/src/main/java/app/suhasdissa/memerize/ui/screens/primary/RedditMemeScreen.kt b/app/src/main/java/app/suhasdissa/memerize/ui/screens/primary/RedditMemeScreen.kt index c541e94..5fa07a5 100644 --- a/app/src/main/java/app/suhasdissa/memerize/ui/screens/primary/RedditMemeScreen.kt +++ b/app/src/main/java/app/suhasdissa/memerize/ui/screens/primary/RedditMemeScreen.kt @@ -7,14 +7,11 @@ All Rights Reserved package app.suhasdissa.memerize.ui.screens.primary -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width @@ -22,7 +19,6 @@ import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.FilterList import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.FilterChip import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme @@ -42,12 +38,12 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import app.suhasdissa.memerize.R -import app.suhasdissa.memerize.backend.model.SortTime import app.suhasdissa.memerize.backend.viewmodels.RedditViewModel import app.suhasdissa.memerize.backend.viewmodels.state.MemeUiState import app.suhasdissa.memerize.ui.components.LoadingScreen import app.suhasdissa.memerize.ui.components.MemeGrid import app.suhasdissa.memerize.ui.components.RetryScreen +import app.suhasdissa.memerize.ui.components.SortBottomSheet import coil.compose.AsyncImage import coil.request.ImageRequest @@ -100,42 +96,6 @@ fun RedditMemeScreen( } ) { paddingValues -> Column(Modifier.padding(paddingValues)) { - redditViewModel.currentSubreddit?.let { - AnimatedVisibility(visible = showFilterButtons) { - Row(modifier.fillMaxWidth(), Arrangement.SpaceEvenly) { - FilterChip( - selected = redditViewModel.currentSortTime == SortTime.TODAY, - onClick = { - showFilterButtons = false - redditViewModel.getMemePhotos(time = SortTime.TODAY) - }, - label = { - Text(stringResource(R.string.reddit_today_btn)) - } - ) - FilterChip( - selected = redditViewModel.currentSortTime == SortTime.WEEK, - onClick = { - showFilterButtons = false - redditViewModel.getMemePhotos(time = SortTime.WEEK) - }, - label = { - Text(stringResource(R.string.reddit_week_btn)) - } - ) - FilterChip( - selected = redditViewModel.currentSortTime == SortTime.MONTH, - onClick = { - showFilterButtons = false - redditViewModel.getMemePhotos(time = SortTime.MONTH) - }, - label = { - Text(stringResource(R.string.reddit_month_btn)) - } - ) - } - } - } when (val memeDataState = redditViewModel.memeUiState) { is MemeUiState.Loading -> LoadingScreen(modifier) is MemeUiState.Error -> RetryScreen( @@ -153,4 +113,10 @@ fun RedditMemeScreen( } } } + if (showFilterButtons) { + SortBottomSheet(currentSort = redditViewModel.currentSortTime, onSelect = { + showFilterButtons = false + redditViewModel.getMemePhotos(sort = it) + }, onDismissRequest = { showFilterButtons = false }) + } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index afdf1ba..e6da5d4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -55,4 +55,9 @@ Set Image Cache Limit Developer Contact Lemmy + Hot + Rising + New + Top + Sort By \ No newline at end of file From 47ee7db5d52eaa292d85a4b50a870136ff55e571 Mon Sep 17 00:00:00 2001 From: Suhas Dissanayake Date: Tue, 15 Aug 2023 14:31:43 +0530 Subject: [PATCH 3/4] Make the video player scrollable --- .../app/suhasdissa/memerize/Destination.kt | 12 ++-- .../memerize/MemerizeApplication.kt | 2 +- .../java/app/suhasdissa/memerize/NavHost.kt | 51 +++++--------- .../backend/viewmodels/PlayerViewModel.kt | 30 ++------ .../memerize/ui/components/MemeCard.kt | 8 +-- .../memerize/ui/components/MemeGrid.kt | 15 ++-- .../memerize/ui/components/VideoCard.kt | 12 ++-- .../memerize/ui/screens/home/HomeScreen.kt | 12 +++- .../ui/screens/primary/LemmyMemeScreen.kt | 13 ++-- .../ui/screens/primary/RedditMemeScreen.kt | 13 ++-- .../ui/screens/secondary/MemeFeedView.kt | 70 +++++++++++++++++++ .../ui/screens/secondary/PhotoView.kt | 14 ++-- .../ui/screens/secondary/VideoView.kt | 47 ++++++------- 13 files changed, 166 insertions(+), 133 deletions(-) create mode 100644 app/src/main/java/app/suhasdissa/memerize/ui/screens/secondary/MemeFeedView.kt diff --git a/app/src/main/java/app/suhasdissa/memerize/Destination.kt b/app/src/main/java/app/suhasdissa/memerize/Destination.kt index 68c4237..235af4b 100644 --- a/app/src/main/java/app/suhasdissa/memerize/Destination.kt +++ b/app/src/main/java/app/suhasdissa/memerize/Destination.kt @@ -18,13 +18,13 @@ sealed class Destination(val route: String) { object Subreddits : Destination("subreddits") object Communities : Destination("communities") object About : Destination("about") - object PhotoView : Destination("memescreen") { - val routeWithArgs = "$route/{url}" - val arguments = listOf(navArgument("url") { type = NavType.StringType }) + object RedditFeed : Destination("reddit_feed") { + val routeWithArgs = "$route/{id}" + val arguments = listOf(navArgument("id") { type = NavType.IntType }) } - object VideoPlayer : Destination("videoplayer") { - val routeWithArgs = "$route/{url}" - val arguments = listOf(navArgument("url") { type = NavType.StringType }) + object LemmyFeed : Destination("lemmy_feed") { + val routeWithArgs = "$route/{id}" + val arguments = listOf(navArgument("id") { type = NavType.IntType }) } } diff --git a/app/src/main/java/app/suhasdissa/memerize/MemerizeApplication.kt b/app/src/main/java/app/suhasdissa/memerize/MemerizeApplication.kt index ef5e325..9ee700c 100644 --- a/app/src/main/java/app/suhasdissa/memerize/MemerizeApplication.kt +++ b/app/src/main/java/app/suhasdissa/memerize/MemerizeApplication.kt @@ -33,7 +33,7 @@ class MemerizeApplication : Application(), ImageLoaderFactory { .respectCacheHeaders(false) .diskCache( DiskCache.Builder() - .directory(cacheDir.resolve("coil")) + .directory(cacheDir.resolve("image_cache")) .maxSizeBytes( preferences.getInt(imageCacheKey, defaultImageCacheSize) * 1024 * 1024L ) diff --git a/app/src/main/java/app/suhasdissa/memerize/NavHost.kt b/app/src/main/java/app/suhasdissa/memerize/NavHost.kt index 457223c..23a544d 100644 --- a/app/src/main/java/app/suhasdissa/memerize/NavHost.kt +++ b/app/src/main/java/app/suhasdissa/memerize/NavHost.kt @@ -9,20 +9,16 @@ package app.suhasdissa.memerize import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable -import app.suhasdissa.memerize.backend.viewmodels.LemmyViewModel -import app.suhasdissa.memerize.backend.viewmodels.PlayerViewModel -import app.suhasdissa.memerize.backend.viewmodels.RedditViewModel import app.suhasdissa.memerize.ui.screens.home.CommunityScreen import app.suhasdissa.memerize.ui.screens.home.HomeScreen import app.suhasdissa.memerize.ui.screens.home.SubredditScreen import app.suhasdissa.memerize.ui.screens.primary.LemmyMemeScreen import app.suhasdissa.memerize.ui.screens.primary.RedditMemeScreen -import app.suhasdissa.memerize.ui.screens.secondary.PhotoView -import app.suhasdissa.memerize.ui.screens.secondary.VideoView +import app.suhasdissa.memerize.ui.screens.secondary.LemmyMemeFeed +import app.suhasdissa.memerize.ui.screens.secondary.RedditMemeFeed import app.suhasdissa.memerize.ui.screens.settings.AboutScreen import app.suhasdissa.memerize.ui.screens.settings.SettingsScreen @@ -32,9 +28,6 @@ fun AppNavHost( onDrawerOpen: () -> Unit, modifier: Modifier = Modifier ) { - val redditViewModel: RedditViewModel = viewModel(factory = RedditViewModel.Factory) - val lemmyViewModel: LemmyViewModel = viewModel(factory = LemmyViewModel.Factory) - val playerViewModel: PlayerViewModel = viewModel(factory = PlayerViewModel.Factory) NavHost( navController = navController, startDestination = Destination.Home.route, @@ -45,9 +38,7 @@ fun AppNavHost( onNavigate = { destination -> navController.navigateTo(destination.route) }, - onDrawerOpen, - redditViewModel = redditViewModel, - lemmyViewModel = lemmyViewModel + onDrawerOpen ) } composable(route = Destination.Settings.route) { @@ -71,12 +62,8 @@ fun AppNavHost( route = Destination.RedditMemeView.route ) { RedditMemeScreen( - redditViewModel = redditViewModel, - onClickMeme = { url -> - navController.navigateTo("${Destination.PhotoView.route}/$url") - }, - onClickVideo = { url -> - navController.navigateTo("${Destination.VideoPlayer.route}/$url") + onClickCard = { id -> + navController.navigateTo("${Destination.RedditFeed.route}/$id") } ) } @@ -84,32 +71,28 @@ fun AppNavHost( route = Destination.LemmyMemeView.route ) { LemmyMemeScreen( - lemmyViewModel = lemmyViewModel, - onClickMeme = { url -> - navController.navigateTo("${Destination.PhotoView.route}/$url") - }, - onClickVideo = { url -> - navController.navigateTo("${Destination.VideoPlayer.route}/$url") + onClickCard = { id -> + navController.navigateTo("${Destination.LemmyFeed.route}/$id") } ) } composable( - route = Destination.PhotoView.routeWithArgs, - arguments = Destination.PhotoView.arguments + route = Destination.RedditFeed.routeWithArgs, + arguments = Destination.RedditFeed.arguments ) { - val imgurl = it.arguments?.getString("url") - if (imgurl != null) { - PhotoView(imgurl) + val id = it.arguments?.getInt("id") + if (id != null) { + RedditMemeFeed(initialPage = id) } } composable( - route = Destination.VideoPlayer.routeWithArgs, - arguments = Destination.VideoPlayer.arguments + route = Destination.LemmyFeed.routeWithArgs, + arguments = Destination.LemmyFeed.arguments ) { - val url = it.arguments?.getString("url") - if (url != null) { - VideoView(url = url, playerViewModel = playerViewModel) + val id = it.arguments?.getInt("id") + if (id != null) { + LemmyMemeFeed(initialPage = id) } } } diff --git a/app/src/main/java/app/suhasdissa/memerize/backend/viewmodels/PlayerViewModel.kt b/app/src/main/java/app/suhasdissa/memerize/backend/viewmodels/PlayerViewModel.kt index f85c187..45e1e57 100644 --- a/app/src/main/java/app/suhasdissa/memerize/backend/viewmodels/PlayerViewModel.kt +++ b/app/src/main/java/app/suhasdissa/memerize/backend/viewmodels/PlayerViewModel.kt @@ -15,30 +15,16 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope -import androidx.lifecycle.viewmodel.initializer -import androidx.lifecycle.viewmodel.viewModelFactory +import androidx.media3.common.Player import androidx.media3.common.util.UnstableApi -import androidx.media3.exoplayer.ExoPlayer -import app.suhasdissa.memerize.MemerizeApplication import app.suhasdissa.memerize.utils.RedditVideoDownloader import kotlinx.coroutines.launch @UnstableApi -class PlayerViewModel(appContext: Context) : ViewModel() { - val player: ExoPlayer = ExoPlayer.Builder(appContext).build() - +class PlayerViewModel() : ViewModel() { var downloadState: DownloadState by mutableStateOf(DownloadState.NotStarted) - fun playPause() { - if (player.isPlaying) player.pause() else player.play() - } - - fun seekTo(to: Long) { - player.seekTo(to) - } - @RequiresApi(Build.VERSION_CODES.O) fun downloadVideo(context: Context, url: String) { viewModelScope.launch { @@ -54,14 +40,8 @@ class PlayerViewModel(appContext: Context) : ViewModel() { } } } +} - companion object { - val Factory: ViewModelProvider.Factory = viewModelFactory { - initializer { - val application = - (this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as MemerizeApplication) // ktlint-disable max-line-length - PlayerViewModel(application) - } - } - } +fun Player.playPause() { + if (isPlaying) pause() else play() } diff --git a/app/src/main/java/app/suhasdissa/memerize/ui/components/MemeCard.kt b/app/src/main/java/app/suhasdissa/memerize/ui/components/MemeCard.kt index fbea54a..96cbe05 100644 --- a/app/src/main/java/app/suhasdissa/memerize/ui/components/MemeCard.kt +++ b/app/src/main/java/app/suhasdissa/memerize/ui/components/MemeCard.kt @@ -8,16 +8,12 @@ All Rights Reserved package app.suhasdissa.memerize.ui.components import androidx.compose.runtime.Composable -import java.net.URLEncoder -import java.nio.charset.StandardCharsets @Composable fun MemeCard( - onClickMeme: (url: String) -> Unit, + onClickMeme: () -> Unit, photo: String, title: String ) { - val encodedImg = URLEncoder.encode(photo, StandardCharsets.UTF_8.toString()) - - ImageCard({ onClickMeme(encodedImg) }, photo, title) + ImageCard({ onClickMeme.invoke() }, photo, title) } diff --git a/app/src/main/java/app/suhasdissa/memerize/ui/components/MemeGrid.kt b/app/src/main/java/app/suhasdissa/memerize/ui/components/MemeGrid.kt index 742edd8..4aa96a3 100644 --- a/app/src/main/java/app/suhasdissa/memerize/ui/components/MemeGrid.kt +++ b/app/src/main/java/app/suhasdissa/memerize/ui/components/MemeGrid.kt @@ -15,7 +15,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyVerticalGrid -import androidx.compose.foundation.lazy.grid.items +import androidx.compose.foundation.lazy.grid.itemsIndexed import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -29,8 +29,7 @@ import app.suhasdissa.memerize.backend.database.entity.Meme @Composable fun MemeGrid( memes: List, - onClickMeme: (url: String) -> Unit, - onClickVideo: (url: String) -> Unit + onClickCard: (id: Int) -> Unit ) { Column( modifier = Modifier @@ -44,11 +43,15 @@ fun MemeGrid( modifier = Modifier.fillMaxWidth(), contentPadding = PaddingValues(8.dp) ) { - items(items = memes) { meme -> + itemsIndexed(items = memes) { index, meme -> if (meme.isVideo) { - VideoCard(onClickVideo, meme.url, meme.title, meme.preview, Modifier) + VideoCard(onClickVideo = { + onClickCard.invoke(index) + }, meme.title, meme.preview, Modifier) } else { - MemeCard(onClickMeme, meme.url, meme.title) + MemeCard(onClickMeme = { + onClickCard.invoke(index) + }, meme.url, meme.title) } } } diff --git a/app/src/main/java/app/suhasdissa/memerize/ui/components/VideoCard.kt b/app/src/main/java/app/suhasdissa/memerize/ui/components/VideoCard.kt index 8cd67f7..3a9b79c 100644 --- a/app/src/main/java/app/suhasdissa/memerize/ui/components/VideoCard.kt +++ b/app/src/main/java/app/suhasdissa/memerize/ui/components/VideoCard.kt @@ -22,25 +22,21 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import java.net.URLEncoder -import java.nio.charset.StandardCharsets @Composable fun VideoCard( - onClickVideo: (url: String) -> Unit, - vidlink: String, + onClickVideo: () -> Unit, title: String, preview: String, modifier: Modifier = Modifier ) { - val encodedLink = URLEncoder.encode(vidlink, StandardCharsets.UTF_8.toString()) Box( contentAlignment = Alignment.Center, modifier = modifier .fillMaxSize() ) { - ImageCard({ onClickVideo(encodedLink) }, preview, title) - Card(modifier.clickable(onClick = { onClickVideo(encodedLink) }), shape = CircleShape) { + ImageCard({ onClickVideo.invoke() }, preview, title) + Card(modifier.clickable(onClick = { onClickVideo.invoke() }), shape = CircleShape) { Icon( modifier = modifier.size(64.dp), imageVector = Icons.Default.PlayCircle, @@ -55,5 +51,5 @@ fun VideoCard( @Preview @Composable fun VideoCardPreview() { - VideoCard(onClickVideo = {}, vidlink = "", title = "Preview", preview = "") + VideoCard(onClickVideo = {}, title = "Preview", preview = "") } diff --git a/app/src/main/java/app/suhasdissa/memerize/ui/screens/home/HomeScreen.kt b/app/src/main/java/app/suhasdissa/memerize/ui/screens/home/HomeScreen.kt index 213f6c1..9032c20 100644 --- a/app/src/main/java/app/suhasdissa/memerize/ui/screens/home/HomeScreen.kt +++ b/app/src/main/java/app/suhasdissa/memerize/ui/screens/home/HomeScreen.kt @@ -7,6 +7,7 @@ All Rights Reserved package app.suhasdissa.memerize.ui.screens.home +import androidx.activity.ComponentActivity import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn @@ -27,6 +28,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel @@ -50,8 +52,14 @@ fun HomeScreen( lemmyCommunityViewModel: LemmyCommunityViewModel = viewModel( factory = LemmyCommunityViewModel.Factory ), - redditViewModel: RedditViewModel, - lemmyViewModel: LemmyViewModel + redditViewModel: RedditViewModel = viewModel( + LocalContext.current as ComponentActivity, + factory = RedditViewModel.Factory + ), + lemmyViewModel: LemmyViewModel = viewModel( + LocalContext.current as ComponentActivity, + factory = LemmyViewModel.Factory + ) ) { val subreddits by redditCommunityViewModel.communities.collectAsState() val communities by lemmyCommunityViewModel.communities.collectAsState() diff --git a/app/src/main/java/app/suhasdissa/memerize/ui/screens/primary/LemmyMemeScreen.kt b/app/src/main/java/app/suhasdissa/memerize/ui/screens/primary/LemmyMemeScreen.kt index 89ed95d..f911e3f 100644 --- a/app/src/main/java/app/suhasdissa/memerize/ui/screens/primary/LemmyMemeScreen.kt +++ b/app/src/main/java/app/suhasdissa/memerize/ui/screens/primary/LemmyMemeScreen.kt @@ -7,6 +7,7 @@ All Rights Reserved package app.suhasdissa.memerize.ui.screens.primary +import androidx.activity.ComponentActivity import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -37,6 +38,7 @@ import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp +import androidx.lifecycle.viewmodel.compose.viewModel import app.suhasdissa.memerize.R import app.suhasdissa.memerize.backend.viewmodels.LemmyViewModel import app.suhasdissa.memerize.backend.viewmodels.state.MemeUiState @@ -51,9 +53,11 @@ import coil.request.ImageRequest @Composable fun LemmyMemeScreen( modifier: Modifier = Modifier, - lemmyViewModel: LemmyViewModel, - onClickMeme: (url: String) -> Unit, - onClickVideo: (url: String) -> Unit + lemmyViewModel: LemmyViewModel = viewModel( + LocalContext.current as ComponentActivity, + factory = LemmyViewModel.Factory + ), + onClickCard: (Int) -> Unit ) { var showFilterButtons by remember { mutableStateOf(false) } Scaffold( @@ -107,8 +111,7 @@ fun LemmyMemeScreen( is MemeUiState.Success -> MemeGrid( memeDataState.memes, - onClickMeme, - onClickVideo + onClickCard ) } } diff --git a/app/src/main/java/app/suhasdissa/memerize/ui/screens/primary/RedditMemeScreen.kt b/app/src/main/java/app/suhasdissa/memerize/ui/screens/primary/RedditMemeScreen.kt index 5fa07a5..7c6af2e 100644 --- a/app/src/main/java/app/suhasdissa/memerize/ui/screens/primary/RedditMemeScreen.kt +++ b/app/src/main/java/app/suhasdissa/memerize/ui/screens/primary/RedditMemeScreen.kt @@ -7,6 +7,7 @@ All Rights Reserved package app.suhasdissa.memerize.ui.screens.primary +import androidx.activity.ComponentActivity import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -37,6 +38,7 @@ import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp +import androidx.lifecycle.viewmodel.compose.viewModel import app.suhasdissa.memerize.R import app.suhasdissa.memerize.backend.viewmodels.RedditViewModel import app.suhasdissa.memerize.backend.viewmodels.state.MemeUiState @@ -51,9 +53,11 @@ import coil.request.ImageRequest @Composable fun RedditMemeScreen( modifier: Modifier = Modifier, - redditViewModel: RedditViewModel, - onClickMeme: (url: String) -> Unit, - onClickVideo: (url: String) -> Unit + redditViewModel: RedditViewModel = viewModel( + LocalContext.current as ComponentActivity, + factory = RedditViewModel.Factory + ), + onClickCard: (Int) -> Unit ) { var showFilterButtons by remember { mutableStateOf(false) } Scaffold( @@ -107,8 +111,7 @@ fun RedditMemeScreen( is MemeUiState.Success -> MemeGrid( memeDataState.memes, - onClickMeme, - onClickVideo + onClickCard ) } } diff --git a/app/src/main/java/app/suhasdissa/memerize/ui/screens/secondary/MemeFeedView.kt b/app/src/main/java/app/suhasdissa/memerize/ui/screens/secondary/MemeFeedView.kt new file mode 100644 index 0000000..1f294f9 --- /dev/null +++ b/app/src/main/java/app/suhasdissa/memerize/ui/screens/secondary/MemeFeedView.kt @@ -0,0 +1,70 @@ +/******************************************************************************* +Created By Suhas Dissanayake on 8/15/23, 12:48 PM +Copyright (c) 2023 +https://github.com/SuhasDissa/ +All Rights Reserved + ******************************************************************************/ + +package app.suhasdissa.memerize.ui.screens.secondary + +import androidx.activity.ComponentActivity +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.pager.VerticalPager +import androidx.compose.foundation.pager.rememberPagerState +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.lifecycle.viewmodel.compose.viewModel +import app.suhasdissa.memerize.backend.database.entity.Meme +import app.suhasdissa.memerize.backend.viewmodels.LemmyViewModel +import app.suhasdissa.memerize.backend.viewmodels.RedditViewModel +import app.suhasdissa.memerize.backend.viewmodels.state.MemeUiState + +@Composable +fun RedditMemeFeed( + initialPage: Int, + redditViewModel: RedditViewModel = viewModel( + LocalContext.current as ComponentActivity, + factory = RedditViewModel.Factory + ) +) { + when (val state = redditViewModel.memeUiState) { + is MemeUiState.Success -> MemeFeedView(initialPage, memes = state.memes) + else -> {} + } +} + +@Composable +fun LemmyMemeFeed( + initialPage: Int, + lemmyViewModel: LemmyViewModel = viewModel( + LocalContext.current as ComponentActivity, + factory = LemmyViewModel.Factory + ) +) { + when (val state = lemmyViewModel.memeUiState) { + is MemeUiState.Success -> MemeFeedView(initialPage, memes = state.memes) + else -> {} + } +} + +@OptIn(ExperimentalFoundationApi::class) +@Composable +private fun MemeFeedView(initialPage: Int, memes: List) { + val pagerState = rememberPagerState( + initialPage = initialPage, + initialPageOffsetFraction = 0f + ) { + memes.size + } + VerticalPager(modifier = Modifier.fillMaxSize(), state = pagerState) { + with(memes[it]) { + if (isVideo) { + VideoView(this, playWhenReady = (it == pagerState.currentPage)) + } else { + PhotoView(this) + } + } + } +} diff --git a/app/src/main/java/app/suhasdissa/memerize/ui/screens/secondary/PhotoView.kt b/app/src/main/java/app/suhasdissa/memerize/ui/screens/secondary/PhotoView.kt index 96da1f8..f304094 100644 --- a/app/src/main/java/app/suhasdissa/memerize/ui/screens/secondary/PhotoView.kt +++ b/app/src/main/java/app/suhasdissa/memerize/ui/screens/secondary/PhotoView.kt @@ -49,21 +49,18 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import app.suhasdissa.memerize.R +import app.suhasdissa.memerize.backend.database.entity.Meme import app.suhasdissa.memerize.backend.viewmodels.DownloadState import app.suhasdissa.memerize.backend.viewmodels.PhotoViewModel import coil.compose.AsyncImage -import coil.request.ImageRequest import java.lang.Float.max -import java.net.URLDecoder -import java.nio.charset.StandardCharsets @Composable fun PhotoView( - photo: String, + meme: Meme, photoViewModel: PhotoViewModel = viewModel() ) { val context = LocalContext.current - val photoUrl = remember { URLDecoder.decode(photo, StandardCharsets.UTF_8.toString()) } Column(Modifier.fillMaxSize(), verticalArrangement = Arrangement.SpaceEvenly) { var scale by remember { mutableFloatStateOf(1f) } var offsetX by remember { mutableFloatStateOf(1f) } @@ -93,8 +90,7 @@ fun PhotoView( contentAlignment = Alignment.Center ) { AsyncImage( - model = ImageRequest.Builder(context = LocalContext.current).data(photoUrl) - .crossfade(true).build(), + model = meme.url, contentDescription = stringResource(R.string.meme_photo), contentScale = ContentScale.Fit, modifier = Modifier @@ -124,7 +120,7 @@ fun PhotoView( ) { IconButton(onClick = { view.playSoundEffect(SoundEffectConstants.CLICK) - photoViewModel.savePhotoToDisk(photoUrl, context) + photoViewModel.savePhotoToDisk(meme.url, context) }) { Icon( imageVector = when (photoViewModel.downloadState) { @@ -139,7 +135,7 @@ fun PhotoView( } IconButton(onClick = { view.playSoundEffect(SoundEffectConstants.CLICK) - photoViewModel.shareImage(photoUrl, context) + photoViewModel.shareImage(meme.url, context) }) { Icon( imageVector = Icons.Default.Share, diff --git a/app/src/main/java/app/suhasdissa/memerize/ui/screens/secondary/VideoView.kt b/app/src/main/java/app/suhasdissa/memerize/ui/screens/secondary/VideoView.kt index 5959b5a..2b950dc 100644 --- a/app/src/main/java/app/suhasdissa/memerize/ui/screens/secondary/VideoView.kt +++ b/app/src/main/java/app/suhasdissa/memerize/ui/screens/secondary/VideoView.kt @@ -51,69 +51,70 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalView import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import androidx.lifecycle.viewmodel.compose.viewModel import androidx.media3.common.MediaItem import androidx.media3.common.Player +import androidx.media3.exoplayer.ExoPlayer import androidx.media3.ui.PlayerView import app.suhasdissa.memerize.R +import app.suhasdissa.memerize.backend.database.entity.Meme import app.suhasdissa.memerize.backend.viewmodels.DownloadState import app.suhasdissa.memerize.backend.viewmodels.PlayerViewModel +import app.suhasdissa.memerize.backend.viewmodels.playPause import app.suhasdissa.memerize.utils.PlayerState import app.suhasdissa.memerize.utils.isPlayingState import app.suhasdissa.memerize.utils.positionAndDurationState import app.suhasdissa.memerize.utils.shareUrl -import java.net.URLDecoder -import java.nio.charset.StandardCharsets @Composable fun VideoView( - url: String, - modifier: Modifier = Modifier, - playerViewModel: PlayerViewModel = viewModel(factory = PlayerViewModel.Factory) + meme: Meme, + playWhenReady: Boolean = false, + playerViewModel: PlayerViewModel = viewModel() ) { - val decodedUrl = remember { URLDecoder.decode(url, StandardCharsets.UTF_8.toString()) } - + val context = LocalContext.current + val player = remember(context) { ExoPlayer.Builder(context).build() } + player.playWhenReady = playWhenReady DisposableEffect(Unit) { - with(playerViewModel.player) { - val mediaItem = MediaItem.Builder().setUri(decodedUrl).build() + with(player) { + val mediaItem = MediaItem.Builder().setUri(meme.url).build() setMediaItem(mediaItem) - playWhenReady = true prepare() onDispose { - stop() + player.release() } } } - Column(modifier.fillMaxSize(), verticalArrangement = Arrangement.SpaceEvenly) { + Column(Modifier.fillMaxSize(), verticalArrangement = Arrangement.SpaceEvenly) { Box( - modifier = modifier + modifier = Modifier .weight(1f) .fillMaxWidth(), contentAlignment = Alignment.Center ) { AndroidView(factory = { context -> PlayerView(context).apply { - player = playerViewModel.player + this.player = player useController = false } }, modifier = Modifier.fillMaxSize()) } - PlayerController(playerViewModel, decodedUrl) + PlayerController(player, playerViewModel, meme.url) } } @SuppressLint("UnsafeOptInUsageError") @Composable fun PlayerController( - playerViewModel: PlayerViewModel = viewModel(factory = PlayerViewModel.Factory), + player: Player, + playerViewModel: PlayerViewModel = viewModel(), decodedUrl: String ) { val view = LocalView.current - with(playerViewModel.player) { + with(player) { Column(Modifier.padding(16.dp)) { val positionAndDuration by positionAndDurationState() Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) { @@ -128,7 +129,7 @@ fun PlayerController( ), onValueChangeFinished = { tempSliderPosition?.let { - playerViewModel.seekTo(it.toLong()) + player.seekTo(it.toLong()) } tempSliderPosition = null } @@ -180,7 +181,7 @@ fun PlayerController( IconButton( onClick = { view.playSoundEffect(SoundEffectConstants.CLICK) - playerViewModel.playPause() + player.playPause() }, modifier = Modifier.padding(8.dp) ) { @@ -250,9 +251,3 @@ fun PlayerController( } } } - -@Preview(showBackground = true) -@Composable -private fun DefaultPreview() { - PlayerController(decodedUrl = "") -} From 873fcd78e7bd43e549637d93d579dfb25758128f Mon Sep 17 00:00:00 2001 From: Suhas Dissanayake Date: Tue, 15 Aug 2023 18:42:03 +0530 Subject: [PATCH 4/4] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1c17005..da7967b 100644 --- a/README.md +++ b/README.md @@ -43,5 +43,6 @@ alt="Get it on GitHub" height="80">](https://github.com/SuhasDissa/MemerizeApp/releases/latest) -## Translations -[Crowdin Translate](https://crowdin.com/project/memerize) +## Useful Links + +