diff --git a/app/src/main/java/org/pixeldroid/app/MainActivity.kt b/app/src/main/java/org/pixeldroid/app/MainActivity.kt index 9ec525b1..0317efdd 100644 --- a/app/src/main/java/org/pixeldroid/app/MainActivity.kt +++ b/app/src/main/java/org/pixeldroid/app/MainActivity.kt @@ -231,17 +231,12 @@ class MainActivity : BaseThemedWithoutBarActivity() { nameRes = R.string.logout iconicsIcon = GoogleMaterial.Icon.gmd_close }, - primaryDrawerItem { - nameRes = R.string.story_image - iconicsIcon = GoogleMaterial.Icon.gmd_auto_stories - }, ) binding.drawer.onDrawerItemClickListener = { v, drawerItem, position -> when (position){ 1 -> launchActivity(ProfileActivity()) 2 -> launchActivity(SettingsActivity()) 3 -> logOut() - 4 -> launchActivity(StoriesActivity()) } false } diff --git a/app/src/main/java/org/pixeldroid/app/posts/feeds/cachedFeeds/postFeeds/PostFeedFragment.kt b/app/src/main/java/org/pixeldroid/app/posts/feeds/cachedFeeds/postFeeds/PostFeedFragment.kt index 48c13fe4..28b77a80 100644 --- a/app/src/main/java/org/pixeldroid/app/posts/feeds/cachedFeeds/postFeeds/PostFeedFragment.kt +++ b/app/src/main/java/org/pixeldroid/app/posts/feeds/cachedFeeds/postFeeds/PostFeedFragment.kt @@ -12,13 +12,14 @@ import androidx.paging.RemoteMediator import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import org.pixeldroid.app.R -import org.pixeldroid.app.utils.db.dao.feedContent.FeedContentDao import org.pixeldroid.app.posts.StatusViewHolder -import org.pixeldroid.app.posts.feeds.cachedFeeds.FeedViewModel import org.pixeldroid.app.posts.feeds.cachedFeeds.CachedFeedFragment +import org.pixeldroid.app.posts.feeds.cachedFeeds.FeedViewModel import org.pixeldroid.app.posts.feeds.cachedFeeds.ViewModelFactory +import org.pixeldroid.app.stories.StoryCarouselViewHolder import org.pixeldroid.app.utils.api.objects.FeedContentDatabase import org.pixeldroid.app.utils.api.objects.Status +import org.pixeldroid.app.utils.db.dao.feedContent.FeedContentDao import org.pixeldroid.app.utils.displayDimensionsInPx import kotlin.properties.Delegates @@ -40,7 +41,7 @@ class PostFeedFragment: CachedFeedFragment() { adapter = PostsAdapter(requireContext().displayDimensionsInPx()) - home = requireArguments().get("home") as Boolean + home = requireArguments().getBoolean("home") @Suppress("UNCHECKED_CAST") if (home){ @@ -55,7 +56,7 @@ class PostFeedFragment: CachedFeedFragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? + savedInstanceState: Bundle?, ): View? { val view = super.onCreateView(inflater, container, savedInstanceState) @@ -78,17 +79,34 @@ class PostFeedFragment: CachedFeedFragment() { ) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { - return StatusViewHolder.create(parent) + return if(viewType == R.layout.post_fragment){ + StatusViewHolder.create(parent) + } else { + StoryCarouselViewHolder.create(parent) + } } override fun getItemViewType(position: Int): Int { - return R.layout.post_fragment + return if(home && position == 0) R.layout.story_carousel + else R.layout.post_fragment } override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { - val uiModel = getItem(position) as Status? - uiModel?.let { - (holder as StatusViewHolder).bind(it, apiHolder, db, lifecycleScope, displayDimensionsInPx) + if(home && position == 0){ + holder.itemView.visibility = View.GONE + holder.itemView.layoutParams = RecyclerView.LayoutParams(0, 0) + (holder as StoryCarouselViewHolder).bind(apiHolder, lifecycleScope, holder.itemView) + } else { + holder.itemView.visibility = View.VISIBLE + holder.itemView.layoutParams = + RecyclerView.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ) + val uiModel = getItem(if(home) position - 1 else position) as Status? + uiModel?.let { + (holder as StatusViewHolder).bind(it, apiHolder, db, lifecycleScope, displayDimensionsInPx) + } } } } diff --git a/app/src/main/java/org/pixeldroid/app/searchDiscover/SearchDiscoverFragment.kt b/app/src/main/java/org/pixeldroid/app/searchDiscover/SearchDiscoverFragment.kt index 3715c601..b82a0598 100644 --- a/app/src/main/java/org/pixeldroid/app/searchDiscover/SearchDiscoverFragment.kt +++ b/app/src/main/java/org/pixeldroid/app/searchDiscover/SearchDiscoverFragment.kt @@ -1,6 +1,5 @@ package org.pixeldroid.app.searchDiscover -import android.annotation.SuppressLint import android.app.SearchManager import android.content.Context import android.content.Intent @@ -9,22 +8,11 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.core.content.ContextCompat -import androidx.lifecycle.lifecycleScope -import androidx.recyclerview.widget.RecyclerView -import com.bumptech.glide.Glide -import com.google.android.material.carousel.CarouselLayoutManager -import kotlinx.coroutines.launch import org.pixeldroid.app.databinding.FragmentSearchBinding -import org.pixeldroid.app.databinding.StoryCarouselBinding import org.pixeldroid.app.searchDiscover.TrendingActivity.Companion.TRENDING_TAG import org.pixeldroid.app.searchDiscover.TrendingActivity.Companion.TrendingType -import org.pixeldroid.app.stories.StoriesActivity -import org.pixeldroid.app.stories.StoriesActivity.Companion.STORY_CAROUSEL -import org.pixeldroid.app.stories.StoriesActivity.Companion.STORY_CAROUSEL_USER_ID import org.pixeldroid.app.utils.BaseFragment import org.pixeldroid.app.utils.api.PixelfedAPI -import org.pixeldroid.app.utils.api.objects.CarouselUserContainer -import org.pixeldroid.app.utils.api.objects.StoryCarousel import org.pixeldroid.app.utils.bindingLifecycleAware @@ -51,13 +39,6 @@ class SearchDiscoverFragment : BaseFragment() { isSubmitButtonEnabled = true } - val adapter = StoriesListAdapter(::onClickStory) - binding.recyclerView2.adapter = adapter - - loadStories(adapter) - - binding.recyclerView2.layoutManager = CarouselLayoutManager() - return binding.root } @@ -78,68 +59,4 @@ class SearchDiscoverFragment : BaseFragment() { ContextCompat.startActivity(binding.root.context, intent, null) } - private fun onClickStory(carousel: StoryCarousel, userId: String){ - val intent = Intent(requireContext(), StoriesActivity::class.java) - intent.putExtra(STORY_CAROUSEL, carousel) - intent.putExtra(STORY_CAROUSEL_USER_ID, userId) - startActivity(intent) - } - - private fun loadStories(adapter: StoriesListAdapter) { - lifecycleScope.launch { - try{ - val api = apiHolder.api ?: apiHolder.setToCurrentUser() - val carousel = api.carousel() - adapter.initCarousel(carousel) - } catch (exception: Exception){ - //TODO - } - } - } - } - -class StoriesListAdapter(private val listener: (StoryCarousel, String) -> Unit): RecyclerView.Adapter() { - - private var storyCarousel: StoryCarousel? = null - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { - val v = StoryCarouselBinding.inflate(LayoutInflater.from(parent.context), parent, false) - return ViewHolder(v) - } - - override fun onBindViewHolder(holder: ViewHolder, position: Int) { - storyCarousel?.nodes?.get(position)?.let { holder.bindItem(it) } - holder.itemView.setOnClickListener { - storyCarousel?.let { carousel -> - storyCarousel?.nodes?.get(position)?.user?.id?.let { userId -> - listener( - carousel, - userId - ) - } - } - } - } - - override fun getItemCount(): Int { - return storyCarousel?.nodes?.size ?: 0 - } - - @SuppressLint("NotifyDataSetChanged") - fun initCarousel(carousel: StoryCarousel){ - storyCarousel = carousel - notifyDataSetChanged() - } - - - class ViewHolder(var itemBinding: StoryCarouselBinding) : - RecyclerView.ViewHolder(itemBinding.root) { - fun bindItem(user: CarouselUserContainer) { - Glide.with(itemBinding.root).load(user.nodes?.firstOrNull()?.src).into(itemBinding.carouselImageView) - Glide.with(itemBinding.root).load(user.user?.avatar).circleCrop().into(itemBinding.storyAuthorProfilePicture) - - itemBinding.username.text = user.user?.username ?: "" //TODO check which one to use here! - } - } -} \ No newline at end of file diff --git a/app/src/main/java/org/pixeldroid/app/stories/StoryCarouselViewHolder.kt b/app/src/main/java/org/pixeldroid/app/stories/StoryCarouselViewHolder.kt new file mode 100644 index 00000000..9323136c --- /dev/null +++ b/app/src/main/java/org/pixeldroid/app/stories/StoryCarouselViewHolder.kt @@ -0,0 +1,133 @@ +package org.pixeldroid.app.stories + +import android.annotation.SuppressLint +import android.content.Intent +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.lifecycle.LifecycleCoroutineScope +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import kotlinx.coroutines.launch +import org.pixeldroid.app.R +import org.pixeldroid.app.databinding.StoryCarouselAddStoryBinding +import org.pixeldroid.app.databinding.StoryCarouselBinding +import org.pixeldroid.app.databinding.StoryCarouselItemBinding +import org.pixeldroid.app.postCreation.carousel.dpToPx +import org.pixeldroid.app.utils.api.objects.CarouselUserContainer +import org.pixeldroid.app.utils.api.objects.StoryCarousel +import org.pixeldroid.app.utils.di.PixelfedAPIHolder + +class StoryCarouselViewHolder(val binding: StoryCarouselBinding) : RecyclerView.ViewHolder(binding.root) { + + fun bind( + pixelfedAPI: PixelfedAPIHolder, + lifecycleScope: LifecycleCoroutineScope, + itemView: View + ) { + val adapter = StoriesListAdapter() + binding.storyCarousel.adapter = adapter + + loadStories(adapter, lifecycleScope, pixelfedAPI, itemView) + } + + private fun loadStories( + adapter: StoriesListAdapter, + lifecycleScope: LifecycleCoroutineScope, + apiHolder: PixelfedAPIHolder, + itemView: View + ) { + lifecycleScope.launch { + try{ + val api = apiHolder.api ?: apiHolder.setToCurrentUser() + val carousel = api.carousel() + + if (carousel.nodes?.isEmpty() != true) { + itemView.visibility = View.VISIBLE + itemView.layoutParams.height = 200.dpToPx(binding.root.context) + itemView.layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT + + adapter.initCarousel(carousel) + } + + } catch (exception: Exception){ + //TODO + } + } + } + + companion object { + fun create(parent: ViewGroup): StoryCarouselViewHolder { + val itemBinding = StoryCarouselBinding.inflate( + LayoutInflater.from(parent.context), parent, false + ) + return StoryCarouselViewHolder(itemBinding) + } + } +} + + +class StoriesListAdapter : RecyclerView.Adapter() { + + private var storyCarousel: StoryCarousel? = null + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + return if(viewType == R.layout.story_carousel_add_story){ + val v = StoryCarouselAddStoryBinding.inflate(LayoutInflater.from(parent.context), parent, false) + AddViewHolder(v) + } + else { + val v = StoryCarouselItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) + ViewHolder(v) + } + } + + override fun getItemViewType(position: Int): Int { + return if(position == 0) R.layout.story_carousel_add_story + else R.layout.story_carousel_item + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + if(position > 0) { + val carouselPosition = position - 1 + storyCarousel?.nodes?.get(carouselPosition)?.let { (holder as ViewHolder).bindItem(it) } + holder.itemView.setOnClickListener { + storyCarousel?.let { carousel -> + storyCarousel?.nodes?.get(carouselPosition)?.user?.id?.let { userId -> + val intent = Intent(holder.itemView.context, StoriesActivity::class.java) + intent.putExtra(StoriesActivity.STORY_CAROUSEL, carousel) + intent.putExtra(StoriesActivity.STORY_CAROUSEL_USER_ID, userId) + holder.itemView.context.startActivity(intent) + } + } + } + } else { + holder.itemView.setOnClickListener { + //TODO support for adding a story + } + } + } + + override fun getItemCount(): Int { + // If the storyCarousel is not set, the carousel is not shown, so itemCount of 0 + return (storyCarousel?.nodes?.size?.plus(1)) ?: 0 + } + + @SuppressLint("NotifyDataSetChanged") + fun initCarousel(carousel: StoryCarousel){ + storyCarousel = carousel + notifyDataSetChanged() + } + + class AddViewHolder(itemBinding: StoryCarouselAddStoryBinding) : RecyclerView.ViewHolder(itemBinding.root) + + class ViewHolder(private val itemBinding: StoryCarouselItemBinding) : + RecyclerView.ViewHolder(itemBinding.root) { + fun bindItem(user: CarouselUserContainer) { + Glide.with(itemBinding.root).load(user.nodes?.firstOrNull()?.src).into(itemBinding.carouselImageView) + Glide.with(itemBinding.root).load(user.user?.avatar).circleCrop().into(itemBinding.storyAuthorProfilePicture) + + itemBinding.username.text = user.user?.username ?: "" //TODO check which one to use here! + } + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/error_layout.xml b/app/src/main/res/layout/error_layout.xml index 8925f2f2..8c8d19e4 100644 --- a/app/src/main/res/layout/error_layout.xml +++ b/app/src/main/res/layout/error_layout.xml @@ -1,17 +1,17 @@ - + tools:visibility="visible"> + app:layout_constraintTop_toBottomOf="@+id/search"> - - \ No newline at end of file diff --git a/app/src/main/res/layout/story_carousel.xml b/app/src/main/res/layout/story_carousel.xml index 7eee812f..6c3bb87b 100644 --- a/app/src/main/res/layout/story_carousel.xml +++ b/app/src/main/res/layout/story_carousel.xml @@ -1,50 +1,17 @@ - - - - - - - - - - - - - + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/story_carousel" + android:layout_width="match_parent" + android:paddingVertical="8dp" + android:layout_height="216dp" + tools:listitem="@layout/story_carousel_item" + android:clipChildren="false" + android:clipToPadding="false" + android:orientation="horizontal" + app:layoutManager="com.google.android.material.carousel.CarouselLayoutManager" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/search" /> diff --git a/app/src/main/res/layout/story_carousel_add_story.xml b/app/src/main/res/layout/story_carousel_add_story.xml new file mode 100644 index 00000000..9b0e82c9 --- /dev/null +++ b/app/src/main/res/layout/story_carousel_add_story.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + diff --git a/app/src/main/res/layout/story_carousel_item.xml b/app/src/main/res/layout/story_carousel_item.xml new file mode 100644 index 00000000..5e77571c --- /dev/null +++ b/app/src/main/res/layout/story_carousel_item.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e496d166..37e8f5aa 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -336,4 +336,5 @@ For more info about Pixelfed, you can check here: https://pixelfed.org" Something went wrong sending reply Something went wrong fetching the carousel Sent reply + Add Story diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 1cd53ef5..c014f310 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -483,6 +483,9 @@ + + + @@ -513,6 +516,9 @@ + + + @@ -661,6 +667,17 @@ + + + + + + + + + + + @@ -709,6 +726,14 @@ + + + + + + + + @@ -757,6 +782,14 @@ + + + + + + + + @@ -805,6 +838,14 @@ + + + + + + + + @@ -871,6 +912,17 @@ + + + + + + + + + + + @@ -937,6 +989,17 @@ + + + + + + + + + + + @@ -1003,6 +1066,17 @@ + + + + + + + + + + + @@ -2743,6 +2817,14 @@ + + + + + + + + @@ -2791,6 +2873,14 @@ + + + + + + + + @@ -2839,6 +2929,14 @@ + + + + + + + + @@ -2887,6 +2985,14 @@ + + + + + + + + @@ -2935,6 +3041,14 @@ + + + + + + + + @@ -3015,6 +3129,14 @@ + + + + + + + + @@ -3063,6 +3185,14 @@ + + + + + + + + @@ -3111,6 +3241,14 @@ + + + + + + + + @@ -3159,6 +3297,14 @@ + + + + + + + + @@ -3207,6 +3353,14 @@ + + + + + + + + @@ -3255,6 +3409,14 @@ + + + + + + + + @@ -3303,6 +3465,14 @@ + + + + + + + + @@ -3351,6 +3521,14 @@ + + + + + + + + @@ -3399,6 +3577,14 @@ + + + + + + + + @@ -3447,6 +3633,14 @@ + + + + + + + + @@ -3495,6 +3689,14 @@ + + + + + + + + @@ -3543,6 +3745,14 @@ + + + + + + + + @@ -3591,6 +3801,14 @@ + + + + + + + + @@ -3639,6 +3857,14 @@ + + + + + + + + @@ -3687,6 +3913,14 @@ + + + + + + + + @@ -3735,6 +3969,14 @@ + + + + + + + + @@ -3783,6 +4025,14 @@ + + + + + + + + @@ -3839,6 +4089,14 @@ + + + + + + + + @@ -3887,6 +4145,14 @@ + + + + + + + + @@ -3935,6 +4201,14 @@ + + + + + + + + @@ -3983,6 +4257,14 @@ + + + + + + + + @@ -4055,6 +4337,14 @@ + + + + + + + + @@ -4103,6 +4393,14 @@ + + + + + + + + @@ -4151,6 +4449,14 @@ + + + + + + + + @@ -4199,6 +4505,14 @@ + + + + + + + + @@ -4247,6 +4561,14 @@ + + + + + + + + @@ -4295,6 +4617,14 @@ + + + + + + + + @@ -4343,6 +4673,14 @@ + + + + + + + + @@ -4391,6 +4729,14 @@ + + + + + + + + @@ -4439,6 +4785,14 @@ + + + + + + + + @@ -4487,6 +4841,14 @@ + + + + + + + + @@ -4535,6 +4897,14 @@ + + + + + + + + @@ -4583,6 +4953,14 @@ + + + + + + + + @@ -4631,6 +5009,14 @@ + + + + + + + + @@ -4679,6 +5065,14 @@ + + + + + + + + @@ -4727,6 +5121,14 @@ + + + + + + + + @@ -4775,6 +5177,14 @@ + + + + + + + + @@ -4823,6 +5233,14 @@ + + + + + + + + @@ -4871,6 +5289,14 @@ + + + + + + + + @@ -5126,6 +5552,9 @@ + + +