WIP perfil

This commit is contained in:
Erik Cavazos 2023-07-31 00:25:25 -06:00
parent b719cce98d
commit 0ab027b635
32 changed files with 653 additions and 359 deletions

View File

@ -18,7 +18,7 @@
<PersistentState>
<option name="values">
<map>
<entry key="url" value="file:/$USER_HOME$/AppData/Local/Android/Sdk/icons/material/materialicons/pending/baseline_pending_24.xml" />
<entry key="url" value="file:/$USER_HOME$/AppData/Local/Android/Sdk/icons/material/materialicons/audio_file/baseline_audio_file_24.xml" />
</map>
</option>
</PersistentState>
@ -28,7 +28,7 @@
</option>
<option name="values">
<map>
<entry key="outputName" value="baseline_pending_24" />
<entry key="outputName" value="baseline_audio_file_24" />
<entry key="sourceFile" value="C:\Users\erike\C:\Users\erike\Downloads\comments-solid.svg" />
</map>
</option>

2
.idea/kotlinc.xml generated
View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="1.8.0" />
<option name="version" value="1.8.20" />
</component>
</project>

94
.idea/navEditor.xml generated
View File

@ -135,8 +135,20 @@
<LayoutPositions>
<option name="myPosition">
<Point>
<option name="x" value="256" />
<option name="y" value="12" />
<option name="x" value="192" />
<option name="y" value="-141" />
</Point>
</option>
</LayoutPositions>
</value>
</entry>
<entry key="blockProfileFragment">
<value>
<LayoutPositions>
<option name="myPosition">
<Point>
<option name="x" value="191" />
<option name="y" value="-446" />
</Point>
</option>
</LayoutPositions>
@ -147,10 +159,44 @@
<LayoutPositions>
<option name="myPosition">
<Point>
<option name="x" value="12" />
<option name="y" value="12" />
<option name="x" value="-374" />
<option name="y" value="-122" />
</Point>
</option>
<option name="myPositions">
<map>
<entry key="action_discussionsFragment_to_audiosFragment">
<value>
<LayoutPositions />
</value>
</entry>
<entry key="action_discussionsFragment_to_blockProfileFragment">
<value>
<LayoutPositions />
</value>
</entry>
<entry key="action_discussionsFragment_to_imagesFragment">
<value>
<LayoutPositions />
</value>
</entry>
<entry key="action_discussionsFragment_to_mainFollowersFragment">
<value>
<LayoutPositions />
</value>
</entry>
<entry key="action_discussionsFragment_to_reportProfileFragment">
<value>
<LayoutPositions />
</value>
</entry>
<entry key="action_discussionsFragment_to_userLinkFragment">
<value>
<LayoutPositions />
</value>
</entry>
</map>
</option>
</LayoutPositions>
</value>
</entry>
@ -159,8 +205,44 @@
<LayoutPositions>
<option name="myPosition">
<Point>
<option name="x" value="12" />
<option name="y" value="368" />
<option name="x" value="198" />
<option name="y" value="164" />
</Point>
</option>
</LayoutPositions>
</value>
</entry>
<entry key="mainFollowersFragment">
<value>
<LayoutPositions>
<option name="myPosition">
<Point>
<option name="x" value="-266" />
<option name="y" value="274" />
</Point>
</option>
</LayoutPositions>
</value>
</entry>
<entry key="reportProfileFragment">
<value>
<LayoutPositions>
<option name="myPosition">
<Point>
<option name="x" value="-83" />
<option name="y" value="327" />
</Point>
</option>
</LayoutPositions>
</value>
</entry>
<entry key="userLinkFragment">
<value>
<LayoutPositions>
<option name="myPosition">
<Point>
<option name="x" value="-123" />
<option name="y" value="-402" />
</Point>
</option>
</LayoutPositions>

View File

@ -6,6 +6,7 @@ plugins {
id 'com.google.dagger.hilt.android'
id 'org.jetbrains.kotlin.plugin.serialization' version '1.8.0'
id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin'
id 'androidx.navigation.safeargs.kotlin'
}
android {
@ -32,6 +33,7 @@ android {
}
}
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
@ -41,6 +43,7 @@ android {
}
dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3'
implementation 'androidx.core:core-ktx:1.10.1'
implementation 'androidx.appcompat:appcompat:1.6.1'

View File

@ -29,6 +29,7 @@
<activity android:name=".settings.ui.SettingsActivity" android:theme="@style/Theme.Isolaatti"/>
<activity android:name=".posting.posts.ui.CreatePostActivity" android:theme="@style/Theme.Isolaatti" android:windowSoftInputMode="adjustResize"/>
<activity android:name=".posting.PostViewerActivity" android:theme="@style/Theme.Isolaatti"/>
<activity android:name=".drafts.ui.DraftsActivity" android:theme="@style/Theme.Isolaatti"/>
</application>
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

View File

@ -0,0 +1,17 @@
package com.isolaatti.drafts.ui
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.isolaatti.databinding.ActivityDraftsBinding
class DraftsActivity : AppCompatActivity() {
lateinit var binding: ActivityDraftsBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityDraftsBinding.inflate(layoutInflater)
setContentView(binding.root)
}
}

View File

@ -21,6 +21,7 @@ import com.isolaatti.BuildConfig
import com.isolaatti.R
import com.isolaatti.common.ErrorMessageViewModel
import com.isolaatti.databinding.FragmentFeedBinding
import com.isolaatti.drafts.ui.DraftsActivity
import com.isolaatti.home.presentation.FeedViewModel
import com.isolaatti.posting.PostViewerActivity
import com.isolaatti.posting.posts.presentation.PostsViewModel
@ -104,6 +105,10 @@ class FeedFragment : Fragment(), OnUserInteractedWithPostCallback {
startActivity(Intent(requireActivity(), ProfileActivity::class.java))
true
}
R.id.drafts_menu_item -> {
startActivity(Intent(requireActivity(), DraftsActivity::class.java))
true
}
R.id.settings_menu_item -> {
startActivity(Intent(requireActivity(), SettingsActivity::class.java))
true
@ -128,18 +133,18 @@ class FeedFragment : Fragment(), OnUserInteractedWithPostCallback {
viewBinding.feedRecyclerView.adapter = adapter
viewBinding.feedRecyclerView.layoutManager = LinearLayoutManager(requireContext())
viewBinding.refreshButton.setOnClickListener {
viewModel.getFeed(refresh = true)
}
// viewBinding.refreshButton.setOnClickListener {
// viewModel.getFeed(refresh = true)
// }
viewBinding.swipeToRefresh.setOnRefreshListener {
viewModel.getFeed(refresh = true)
viewBinding.swipeToRefresh.isRefreshing = false
}
viewBinding.loadMoreButton.setOnClickListener {
viewModel.getFeed(refresh = false)
}
// viewBinding.loadMoreButton.setOnClickListener {
// viewModel.getFeed(refresh = false)
// }
viewBinding.topAppBar.setOnMenuItemClickListener {
when(it.itemId) {
@ -175,17 +180,17 @@ class FeedFragment : Fragment(), OnUserInteractedWithPostCallback {
}
}
viewModel.loadingPosts.observe(viewLifecycleOwner) {
viewBinding.progressBarLoading.visibility = if(it) View.VISIBLE else View.GONE
viewBinding.loadMoreButton.visibility = if(it) View.GONE else View.VISIBLE
}
viewModel.noMoreContent.observe(viewLifecycleOwner) {
val visibility = if(it) View.VISIBLE else View.GONE
viewBinding.noMoreContentToShowTextView.visibility = visibility
viewBinding.refreshButton.visibility = visibility
viewBinding.loadMoreButton.visibility = if(it) View.GONE else View.VISIBLE
}
// viewModel.loadingPosts.observe(viewLifecycleOwner) {
// viewBinding.progressBarLoading.visibility = if(it) View.VISIBLE else View.GONE
// viewBinding.loadMoreButton.visibility = if(it) View.GONE else View.VISIBLE
// }
//
// viewModel.noMoreContent.observe(viewLifecycleOwner) {
// val visibility = if(it) View.VISIBLE else View.GONE
// viewBinding.noMoreContentToShowTextView.visibility = visibility
// viewBinding.refreshButton.visibility = visibility
// viewBinding.loadMoreButton.visibility = if(it) View.GONE else View.VISIBLE
// }
viewModel.errorLoading.observe(viewLifecycleOwner) {
errorViewModel.error.postValue(it)

View File

@ -1,13 +1,36 @@
package com.isolaatti.posting.posts.data.remote
import com.google.gson.TypeAdapter
import com.google.gson.annotations.JsonAdapter
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonWriter
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
data class FeedFilterDto(
val includeAudio: String,
val includeFromSquads: String,
val dataRange: DataRange
val dateRange: DataRange
) {
class LocalDateTimeJsonAdapter : TypeAdapter<LocalDate>() {
override fun write(out: JsonWriter?, value: LocalDate?) {
if(value != null) {
out?.jsonValue("\"${value.format(DateTimeFormatter.ISO_LOCAL_DATE)}\"")
}
}
override fun read(`in`: JsonReader?): LocalDate {
return LocalDate.parse(`in`.toString())
}
}
data class DataRange(
val enabled: Boolean,
val from: String,
val to: String
@JsonAdapter(LocalDateTimeJsonAdapter::class)
val from: LocalDate,
@JsonAdapter(LocalDateTimeJsonAdapter::class)
val to: LocalDate
)
}

View File

@ -5,6 +5,7 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.isolaatti.posting.posts.data.remote.FeedDto
import com.isolaatti.posting.posts.data.remote.FeedFilterDto
import com.isolaatti.profile.data.remote.UserProfileDto
import com.isolaatti.profile.domain.ProfileRepository
import com.isolaatti.profile.domain.use_case.GetProfile
@ -16,6 +17,10 @@ import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.Month
import javax.inject.Inject
@HiltViewModel
@ -37,6 +42,25 @@ class ProfileViewModel @Inject constructor(private val getProfileUseCase: GetPro
}
fun getPosts(profileId: Int, refresh: Boolean) {
viewModelScope.launch {
getProfilePosts(
profileId,
-1,
false,
FeedFilterDto(
"both",
"both",
FeedFilterDto.DataRange(
false,
LocalDate.of(2020, 1, 1),
LocalDate.now()
)
)
).onEach {
if(it is Resource.Success) {
_posts.postValue(it.data!!)
}
}.flowOn(Dispatchers.IO).launchIn(this)
}
}
}

View File

@ -0,0 +1,8 @@
package com.isolaatti.profile.ui
import androidx.fragment.app.Fragment
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class BlockProfileFragment : Fragment() {
}

View File

@ -4,13 +4,62 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.activity.viewModels
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.appbar.AppBarLayout
import com.isolaatti.BuildConfig
import com.isolaatti.R
import com.isolaatti.databinding.FragmentDiscussionsBinding
import com.isolaatti.posting.common.domain.OnUserInteractedWithPostCallback
import com.isolaatti.posting.posts.data.remote.FeedDto
import com.isolaatti.posting.posts.presentation.PostsRecyclerViewAdapter
import com.isolaatti.profile.data.remote.UserProfileDto
import com.isolaatti.profile.presentation.ProfileViewModel
import com.isolaatti.utils.PicassoImagesPluginDef
import com.isolaatti.utils.UrlGen
import com.squareup.picasso.Picasso
import dagger.hilt.android.AndroidEntryPoint
import dagger.hilt.android.lifecycle.HiltViewModel
import io.noties.markwon.AbstractMarkwonPlugin
import io.noties.markwon.Markwon
import io.noties.markwon.MarkwonConfiguration
import io.noties.markwon.image.destination.ImageDestinationProcessorRelativeToAbsolute
import io.noties.markwon.linkify.LinkifyPlugin
class DiscussionsFragment : Fragment() {
@AndroidEntryPoint
class DiscussionsFragment : Fragment(), OnUserInteractedWithPostCallback {
lateinit var viewBinding: FragmentDiscussionsBinding
private val viewModel: ProfileViewModel by viewModels()
private var userId: Int? = null
private var title = ""
lateinit var feedAdapter: PostsRecyclerViewAdapter
private val profileObserver = Observer<UserProfileDto> { profile ->
Picasso.get()
.load(UrlGen.userProfileImage(profile.id))
.into(viewBinding.profileImageView)
title = profile.name
viewBinding.textViewUsername.text = profile.name
viewBinding.textViewDescription.text = profile.descriptionText
}
private val postsObserver: Observer<FeedDto> = Observer {
feedAdapter.updateList(it, null)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
userId = (requireActivity()).intent.extras?.getInt(ProfileActivity.EXTRA_USER_ID)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@ -20,4 +69,89 @@ class DiscussionsFragment : Fragment() {
return viewBinding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
var scrollRange = -1
var isShow = false
viewBinding.topAppBarLayout.addOnOffsetChangedListener { appBarLayout, verticalOffset ->
if (scrollRange == -1) scrollRange = appBarLayout.totalScrollRange
if (scrollRange + verticalOffset == 0) {
viewBinding.collapsingToolbarLayout.title = title
isShow = true
} else if (isShow) {
viewBinding.collapsingToolbarLayout.title = " "
}
}
viewBinding.topAppBar.setNavigationOnClickListener {
findNavController().popBackStack()
}
viewModel.profile.observe(viewLifecycleOwner, profileObserver)
viewModel.posts.observe(viewLifecycleOwner, postsObserver)
userId?.let {
viewModel.getProfile(it)
viewModel.getPosts(it, true)
}
val markwon = Markwon.builder(requireContext())
.usePlugin(object: AbstractMarkwonPlugin() {
override fun configureConfiguration(builder: MarkwonConfiguration.Builder) {
builder
.imageDestinationProcessor(
ImageDestinationProcessorRelativeToAbsolute
.create(BuildConfig.backend))
}
})
.usePlugin(PicassoImagesPluginDef.picassoImagePlugin)
.usePlugin(LinkifyPlugin.create())
.build()
feedAdapter = PostsRecyclerViewAdapter(markwon, this, null)
viewBinding.feedRecyclerView.adapter = feedAdapter
viewBinding.feedRecyclerView.layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
viewBinding.bottomAppBar.setOnMenuItemClickListener {
when(it.itemId) {
R.id.audios_menu_item -> {
findNavController().navigate(DiscussionsFragmentDirections.actionDiscussionsFragmentToAudiosFragment())
true
}
R.id.images_menu_item -> {
findNavController().navigate(DiscussionsFragmentDirections.actionDiscussionsFragmentToImagesFragment())
true
}
else -> { false }
}
}
}
override fun onLiked(postId: Long) {
TODO("Not yet implemented")
}
override fun onUnLiked(postId: Long) {
TODO("Not yet implemented")
}
override fun onComment(postId: Long) {
TODO("Not yet implemented")
}
override fun onOpenPost(postId: Long) {
TODO("Not yet implemented")
}
override fun onOptions(postId: Long) {
TODO("Not yet implemented")
}
override fun onProfileClick(userId: Int) {
TODO("Not yet implemented")
}
}

View File

@ -0,0 +1,8 @@
package com.isolaatti.profile.ui
import androidx.fragment.app.Fragment
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class MainFollowersFragment : Fragment() {
}

View File

@ -7,73 +7,49 @@ import android.util.Log
import androidx.activity.addCallback
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContentProviderCompat.requireContext
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.findNavController
import androidx.navigation.fragment.NavHostFragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.viewpager.widget.PagerAdapter
import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.adapter.FragmentViewHolder
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.appbar.AppBarLayout.OnOffsetChangedListener
import com.google.android.material.tabs.TabLayoutMediator
import com.isolaatti.BuildConfig
import com.isolaatti.R
import com.isolaatti.databinding.ActivityProfileBinding
import com.isolaatti.posting.common.domain.OnUserInteractedCallback
import com.isolaatti.posting.common.domain.OnUserInteractedWithPostCallback
import com.isolaatti.posting.posts.data.remote.FeedDto
import com.isolaatti.posting.posts.presentation.PostsRecyclerViewAdapter
import com.isolaatti.profile.data.remote.UserProfileDto
import com.isolaatti.profile.presentation.ProfileViewModel
import com.isolaatti.utils.PicassoImagesPluginDef
import com.isolaatti.utils.UrlGen
import com.squareup.picasso.Picasso
import dagger.hilt.android.AndroidEntryPoint
import io.noties.markwon.AbstractMarkwonPlugin
import io.noties.markwon.Markwon
import io.noties.markwon.MarkwonConfiguration
import io.noties.markwon.image.destination.ImageDestinationProcessorRelativeToAbsolute
import io.noties.markwon.linkify.LinkifyPlugin
@AndroidEntryPoint
class ProfileActivity : AppCompatActivity() {
class ProfileActivity : FragmentActivity() {
lateinit var viewBinding: ActivityProfileBinding
private val viewModel: ProfileViewModel by viewModels()
private var userId: Int? = null
private var title = ""
private val profileObserver = Observer<UserProfileDto> { profile ->
Picasso.get()
.load(UrlGen.userProfileImage(profile.id))
.into(viewBinding.profileImageView)
title = profile.name
viewBinding.textViewUsername.text = profile.name
viewBinding.textViewDescription.text = profile.descriptionText
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewBinding = ActivityProfileBinding.inflate(layoutInflater)
setContentView(viewBinding.root)
userId = intent.extras?.getInt(EXTRA_USER_ID)
var scrollRange = -1
var isShow = false
viewBinding.topAppBarLayout.addOnOffsetChangedListener(object: OnOffsetChangedListener {
override fun onOffsetChanged(appBarLayout: AppBarLayout, verticalOffset: Int) {
if (scrollRange == -1) scrollRange = appBarLayout.totalScrollRange
if(scrollRange + verticalOffset == 0) {
viewBinding.collapsingToolbarLayout.title = title
isShow = true
} else if(isShow) {
viewBinding.collapsingToolbarLayout.title = " "
}
}
})
viewBinding.topAppBar.setNavigationOnClickListener {
finish()
}
viewModel.profile.observe(this, profileObserver)
userId?.let { viewModel.getProfile(it) }
}

View File

@ -0,0 +1,8 @@
package com.isolaatti.profile.ui
import androidx.fragment.app.Fragment
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class ReportProfileFragment : Fragment() {
}

View File

@ -0,0 +1,8 @@
package com.isolaatti.profile.ui
import androidx.fragment.app.Fragment
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class UserLinkFragment : Fragment() {
}

View File

@ -1,6 +1,6 @@
package com.isolaatti.utils
abstract class Resource<T> {
sealed class Resource<T> {
class Success<T>(val data: T?): Resource<T>()
class Loading<T>: Resource<T>()
class Error<T>(val errorType: ErrorType? = null): Resource<T>() {

View File

@ -0,0 +1,5 @@
<vector android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@color/on_surface" android:pathData="M14,2H6C4.9,2 4.01,2.9 4.01,4L4,20c0,1.1 0.89,2 1.99,2H18c1.1,0 2,-0.9 2,-2V8L14,2zM16,13h-3v3.75c0,1.24 -1.01,2.25 -2.25,2.25S8.5,17.99 8.5,16.75c0,-1.24 1.01,-2.25 2.25,-2.25c0.46,0 0.89,0.14 1.25,0.38V11h4V13zM13,9V3.5L18.5,9H13z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
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="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM4,12c0,-4.42 3.58,-8 8,-8 1.85,0 3.55,0.63 4.9,1.69L5.69,16.9C4.63,15.55 4,13.85 4,12zM12,20c-1.85,0 -3.55,-0.63 -4.9,-1.69L18.31,7.1C19.37,8.45 20,10.15 20,12c0,4.42 -3.58,8 -8,8z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
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="M16.59,8.59L12,13.17 7.41,8.59 6,10l6,6 6,-6z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
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="M3,18h6v-2L3,16v2zM3,6v2h18L21,6L3,6zM3,13h12v-2L3,11v2z"/>
</vector>

View File

@ -19,18 +19,6 @@
app:layout_constraintTop_toTopOf="parent"
tools:context=".home.FeedFragment">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="@+id/linearLayout">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/topAppBar_layout"
android:layout_width="0dp"
@ -61,60 +49,16 @@
android:id="@+id/swipe_to_refresh"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/topAppBar_layout">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/feed_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:id="@+id/no_more_content_to_show_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/there_is_no_more_content_to_show"
android:textAlignment="center" />
<ImageButton
android:id="@+id/refresh_button"
style="@style/Widget.Material3.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:src="@drawable/baseline_refresh_24" />
<Button
android:id="@+id/load_more_button"
style="@style/Widget.Material3.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="8dp"
android:text="@string/load_more" />
<ProgressBar
android:id="@+id/progress_bar_loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -5,116 +5,12 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/topAppBar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar_layout"
android:layout_width="match_parent"
android:layout_height="410dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
app:contentScrim="@color/purple">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="350dp"
android:orientation="vertical"
android:layout_marginTop="56dp">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/profile_image_view"
android:layout_width="120dp"
android:layout_height="120dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:shapeAppearance="@style/ShapeAppearanceOverlay.Avatar"
tools:srcCompat="@tools:sample/avatars" />
<TextView
android:id="@+id/text_view_username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_weight="1"
android:textSize="20sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/profile_image_view"
tools:text="Erik Cavazos" />
<TextView
android:id="@+id/text_view_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="20dp"
android:maxLines="4"
android:textAlignment="center"
app:layout_constraintTop_toBottomOf="@id/text_view_username"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:text="Hi there, I am software developer!" />
<TextView
android:id="@+id/text_view_following_state"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:textAlignment="center"
android:textStyle="bold"
app:layout_constraintTop_toBottomOf="@id/text_view_description"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:text="Following this profile" />
<com.google.android.material.button.MaterialButton
style="?attr/materialIconButtonFilledTonalStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="8dp"
app:layout_constraintEnd_toStartOf="@id/profile_options_button"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/text_view_following_state" />
<com.google.android.material.button.MaterialButton
android:id="@+id/profile_options_button"
style="?attr/materialIconButtonFilledTonalStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
app:icon="@drawable/baseline_more_horiz_24"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/text_view_following_state"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/top_app_bar"
style="@style/Theme.Isolaatti"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:navigationIcon="@drawable/baseline_arrow_back_24"
app:navigationIconTint="@color/on_surface"
app:layout_collapseMode="pin" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/feed_recycler_view"
<androidx.fragment.app.FragmentContainerView
android:id="@+id/profile_fragment_view"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"/>
app:defaultNavHost="true"
app:navGraph="@navigation/profile_navigation" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -1,15 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/discussionRecycler"
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/topAppBar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="parent"
app:liftOnScrollColor="@color/on_surface">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="56dp">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/profile_image_view"
android:layout_width="120dp"
android:layout_height="120dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:shapeAppearance="@style/ShapeAppearanceOverlay.Avatar"
tools:srcCompat="@tools:sample/avatars" />
<TextView
android:id="@+id/text_view_username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_weight="1"
android:textSize="20sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/profile_image_view"
tools:text="Erik Cavazos" />
<TextView
android:id="@+id/text_view_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="20dp"
android:maxLines="4"
android:textAlignment="center"
app:layout_constraintTop_toBottomOf="@id/text_view_username"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:text="Hi there, I am software developer!" />
<TextView
android:id="@+id/text_view_following_state"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:textAlignment="center"
android:textStyle="bold"
app:layout_constraintTop_toBottomOf="@id/text_view_description"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:text="Following this profile" />
<com.google.android.material.button.MaterialButton
style="?attr/materialIconButtonFilledTonalStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/text_view_following_state" />
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/top_app_bar"
style="@style/Theme.Isolaatti"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:navigationIcon="@drawable/baseline_arrow_back_24"
app:navigationIconTint="@color/on_surface"
app:layout_collapseMode="pin"
app:menu="@menu/profile_menu"/>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="80dp"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/feed_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<com.google.android.material.bottomappbar.BottomAppBar
android:id="@+id/bottomAppBar"
android:layout_width="match_parent"
android:layout_height="80dp"
android:layout_gravity="bottom"
app:menu="@menu/profile_bottom_bar_menu"
style="@style/Widget.Material3.BottomAppBar" />
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_anchor="@id/bottomAppBar"
app:icon="@drawable/baseline_add_24" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -15,17 +15,6 @@
android:layout_height="match_parent"
tools:context=".home.FeedFragment">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="0dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/topAppBar_layout"
android:layout_width="match_parent"
@ -49,53 +38,14 @@
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipe_to_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
android:layout_height="match_parent"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/feed_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:id="@+id/no_more_content_to_show_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="center"
android:layout_marginTop="16dp"
android:text="@string/there_is_no_more_content_to_show"/>
<ImageButton
android:id="@+id/refresh_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/Widget.Material3.Button.TextButton"
android:layout_gravity="center"
android:gravity="center"
android:src="@drawable/baseline_refresh_24"/>
<Button
android:id="@+id/load_more_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="8dp"
style="@style/Widget.Material3.Button.TextButton"
android:text="@string/load_more"/>
<ProgressBar
android:id="@+id/progress_bar_loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</LinearLayout>
</FrameLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -45,4 +45,5 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/profileImageView"
app:layout_constraintTop_toBottomOf="@+id/textViewName" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -6,8 +6,4 @@
android:title="@string/discussion"
android:icon="@drawable/baseline_post_add_24"
app:showAsAction="ifRoom"/>
<item android:id="@+id/menu_item_new_audio"
android:title="@string/add_audio"
android:icon="@drawable/baseline_mic_24"
app:showAsAction="ifRoom"/>
</menu>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/images_menu_item"
android:title="@string/images"
android:icon="@drawable/baseline_image_24"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/audios_menu_item"
android:title="@string/audios"
android:icon="@drawable/baseline_audio_file_24"
app:showAsAction="ifRoom"/>
</menu>

View File

@ -1,5 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:title="Item" />
<item
android:id="@+id/user_link_menu_item"
android:title="@string/user_link"
app:showAsAction="never" />
<item
android:id="@+id/report_profile_menu_item"
android:title="@string/report_profile"
app:showAsAction="never"
android:icon="@drawable/baseline_report_24"/>
<item
android:id="@+id/block_profile_menu_item"
android:title="@string/block_profile"
app:showAsAction="never"
android:icon="@drawable/baseline_block_24" />
</menu>

View File

@ -7,7 +7,26 @@
<fragment
android:id="@+id/discussionsFragment"
android:name="com.isolaatti.profile.ui.DiscussionsFragment"
android:label="DiscussionsFragment" />
android:label="DiscussionsFragment" >
<action
android:id="@+id/action_discussionsFragment_to_audiosFragment"
app:destination="@id/audiosFragment" />
<action
android:id="@+id/action_discussionsFragment_to_imagesFragment"
app:destination="@id/imagesFragment" />
<action
android:id="@+id/action_discussionsFragment_to_blockProfileFragment"
app:destination="@id/blockProfileFragment" />
<action
android:id="@+id/action_discussionsFragment_to_reportProfileFragment"
app:destination="@id/reportProfileFragment" />
<action
android:id="@+id/action_discussionsFragment_to_userLinkFragment"
app:destination="@id/userLinkFragment" />
<action
android:id="@+id/action_discussionsFragment_to_mainFollowersFragment"
app:destination="@id/mainFollowersFragment" />
</fragment>
<fragment
android:id="@+id/audiosFragment"
android:name="com.isolaatti.profile.ui.AudiosFragment"
@ -16,4 +35,20 @@
android:id="@+id/imagesFragment"
android:name="com.isolaatti.profile.ui.ImagesFragment"
android:label="ImagesFragment" />
<fragment
android:id="@+id/blockProfileFragment"
android:name="com.isolaatti.profile.ui.BlockProfileFragment"
android:label="BlockProfileFragment" />
<fragment
android:id="@+id/reportProfileFragment"
android:name="com.isolaatti.profile.ui.ReportProfileFragment"
android:label="ReportProfileFragment" />
<fragment
android:id="@+id/userLinkFragment"
android:name="com.isolaatti.profile.ui.UserLinkFragment"
android:label="UserLinkFragment" />
<fragment
android:id="@+id/mainFollowersFragment"
android:name="com.isolaatti.profile.ui.MainFollowersFragment"
android:label="MainFollowersFragment" />
</navigation>

View File

@ -48,4 +48,13 @@
<string name="what_do_you_want_to_talk_about_markdown_is_compatible_you_can_record_an_audio_if_you_want">What do you want to talk about? Markdown is compatible. You can record an audio if you want.</string>
<string name="posted_successfully">Posted!</string>
<string name="drafts">Drafts</string>
<string name="report_profile">Report profile</string>
<string name="block_profile">Block profile</string>
<string name="sort">Sort</string>
<string name="followers">Followers</string>
<string name="followings">Following</string>
<string name="following_user">Following</string>
<string name="mutually_following">Mutually following</string>
<string name="following_you">Following you</string>
<string name="user_link">User link</string>
</resources>

View File

@ -6,7 +6,9 @@ buildscript {
mavenCentral()
}
dependencies {
def nav_version = "2.6.0"
classpath "com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin:2.0.1"
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
}
}
plugins {