mirror of
https://github.com/sudoxnym/habitica-android.git
synced 2026-04-14 19:56:32 +00:00
Begin implementing party seeking feature
This commit is contained in:
parent
f80c169a3a
commit
fd5661aa9e
15 changed files with 269 additions and 54 deletions
|
|
@ -1,4 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.compose.ui.platform.ComposeView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.compose.ui.platform.ComposeView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/compose_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
android:layout_height="match_parent" />
|
||||
|
|
|
|||
|
|
@ -191,6 +191,12 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:text="@string/members"
|
||||
style="@style/SegmentTitle"/>
|
||||
<Button
|
||||
android:id="@+id/find_new_member"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/find_new_member"
|
||||
style="@style/HabiticaButton.Gray"/>
|
||||
<LinearLayout
|
||||
android:id="@+id/members_wrapper"
|
||||
android:layout_width="match_parent"
|
||||
|
|
@ -208,4 +214,4 @@
|
|||
android:text="@string/leave_party"/>
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
|
|
|||
|
|
@ -67,6 +67,11 @@
|
|||
android:name="com.habitrpg.android.habitica.ui.fragments.social.party.NoPartyFragmentFragment"
|
||||
android:label="@string/sidebar_party">
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/partyInvitationFragment"
|
||||
android:name="com.habitrpg.android.habitica.ui.fragments.social.party.PartyInvitePagerFragment"
|
||||
android:label="@string/sidebar_party">
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/questDetailFragment"
|
||||
android:name="com.habitrpg.android.habitica.ui.fragments.social.QuestDetailFragment">
|
||||
|
|
@ -516,4 +521,4 @@
|
|||
app:argType="string" />
|
||||
<deepLink app:uri="habitica.com/promo/web?url={url}" />
|
||||
</fragment>
|
||||
</navigation>
|
||||
</navigation>
|
||||
|
|
|
|||
|
|
@ -462,4 +462,7 @@ interface ApiService {
|
|||
|
||||
@POST("tasks/{taskID}/needs-work/{userID}")
|
||||
suspend fun markTaskNeedsWork(@Path("taskID") taskID: String, @Path("userID") userID: String): HabitResponse<Task>
|
||||
|
||||
@GET("party-seekers")
|
||||
suspend fun retrievePartySeekingUsers(): HabitResponse<List<Member>>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,6 +96,9 @@ import com.habitrpg.android.habitica.ui.fragments.social.party.NoPartyFragmentFr
|
|||
import com.habitrpg.android.habitica.ui.fragments.social.party.PartyDetailFragment;
|
||||
import com.habitrpg.android.habitica.ui.fragments.social.party.PartyFragment;
|
||||
import com.habitrpg.android.habitica.ui.fragments.social.party.PartyInviteFragment;
|
||||
import com.habitrpg.android.habitica.ui.fragments.social.party.PartyInvitePagerFragment;
|
||||
import com.habitrpg.android.habitica.ui.fragments.social.party.PartySeekingFragment;
|
||||
import com.habitrpg.android.habitica.ui.fragments.social.party.PartySeekingViewModel;
|
||||
import com.habitrpg.android.habitica.ui.fragments.support.BugFixFragment;
|
||||
import com.habitrpg.android.habitica.ui.fragments.support.FAQDetailFragment;
|
||||
import com.habitrpg.android.habitica.ui.fragments.support.FAQOverviewFragment;
|
||||
|
|
@ -376,4 +379,10 @@ public interface UserComponent {
|
|||
void inject(@NotNull AvatarEquipmentFragment avatarEquipmentFragment);
|
||||
|
||||
void inject(@NotNull BirthdayActivity birthdayActivity);
|
||||
|
||||
void inject(@NotNull PartySeekingFragment partySeekingFragment);
|
||||
|
||||
void inject(@NotNull PartySeekingViewModel partySeekingViewModel);
|
||||
|
||||
void inject(@NotNull PartyInvitePagerFragment partyInvitePagerFragment);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -276,4 +276,5 @@ interface ApiClient {
|
|||
suspend fun updateMember(memberID: String, updateData: Map<String, Any?>): Member?
|
||||
suspend fun getHallMember(userId: String): Member?
|
||||
suspend fun markTaskNeedsWork(taskID: String, userID: String): Task?
|
||||
suspend fun retrievePartySeekingUsers() : List<Member>?
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,4 +121,5 @@ interface SocialRepository : BaseRepository {
|
|||
suspend fun blockMember(userID: String): List<String>?
|
||||
fun getMember(userID: String?): Flow<Member?>
|
||||
suspend fun updateMember(memberID: String, key: String, value: Any?): Member?
|
||||
suspend fun retrievePartySeekingUsers(): List<Member>?
|
||||
}
|
||||
|
|
|
|||
|
|
@ -622,6 +622,10 @@ class ApiClientImpl(
|
|||
return process { apiService.markTaskNeedsWork(taskID, userID) }
|
||||
}
|
||||
|
||||
override suspend fun retrievePartySeekingUsers() : List<Member>? {
|
||||
return process { apiService.retrievePartySeekingUsers() }
|
||||
}
|
||||
|
||||
override suspend fun getMember(memberId: String) = processResponse(apiService.getMember(memberId))
|
||||
override suspend fun getMemberWithUsername(username: String) = processResponse(apiService.getMemberWithUsername(username))
|
||||
|
||||
|
|
|
|||
|
|
@ -48,6 +48,10 @@ class SocialRepositoryImpl(
|
|||
return apiClient.updateMember(memberID, mapOf(key to value))
|
||||
}
|
||||
|
||||
override suspend fun retrievePartySeekingUsers() : List<Member>? {
|
||||
return apiClient.retrievePartySeekingUsers()
|
||||
}
|
||||
|
||||
override fun getGroupMembership(id: String) = localRepository.getGroupMembership(userID, id)
|
||||
|
||||
override fun getGroupMemberships(): Flow<List<GroupMembership>> {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import android.widget.TextView
|
|||
import androidx.appcompat.widget.AppCompatEditText
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.components.UserComponent
|
||||
|
|
@ -93,6 +94,9 @@ class PartyDetailFragment : BaseFragment<FragmentPartyDetailBinding>() {
|
|||
binding?.questDetailButton?.setOnClickListener { questDetailButtonClicked() }
|
||||
binding?.leaveButton?.setOnClickListener { leaveParty() }
|
||||
|
||||
binding?.findNewMember?.setOnClickListener {
|
||||
MainNavigationController.navigate(R.id.partyInvitationFragment)
|
||||
}
|
||||
binding?.invitationsView?.setLeader = null
|
||||
|
||||
binding?.invitationsView?.acceptCall = {
|
||||
|
|
@ -153,6 +157,8 @@ class PartyDetailFragment : BaseFragment<FragmentPartyDetailBinding>() {
|
|||
binding?.questImageWrapper?.visibility = View.GONE
|
||||
binding?.questProgressView?.visibility = View.GONE
|
||||
}
|
||||
|
||||
binding?.findNewMember?.isVisible = viewModel?.isLeader == true
|
||||
}
|
||||
|
||||
private fun updateUser(user: User?) {
|
||||
|
|
|
|||
|
|
@ -56,11 +56,10 @@ class PartyFragment : BaseMainFragment<FragmentViewpagerBinding>() {
|
|||
viewModel.groupViewType = GroupViewType.PARTY
|
||||
|
||||
viewModel.getGroupData().observe(
|
||||
viewLifecycleOwner,
|
||||
{
|
||||
updateGroupUI(it)
|
||||
}
|
||||
)
|
||||
viewLifecycleOwner
|
||||
) {
|
||||
updateGroupUI(it)
|
||||
}
|
||||
|
||||
binding?.viewPager?.currentItem = 0
|
||||
|
||||
|
|
|
|||
|
|
@ -1,70 +1,38 @@
|
|||
package com.habitrpg.android.habitica.ui.fragments.social.party
|
||||
|
||||
import android.os.Bundle
|
||||
import android.text.InputType
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.EditText
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.components.UserComponent
|
||||
import com.habitrpg.android.habitica.databinding.FragmentPartyInviteBinding
|
||||
import com.habitrpg.android.habitica.databinding.FragmentComposeBinding
|
||||
import com.habitrpg.android.habitica.helpers.AppConfigManager
|
||||
import com.habitrpg.android.habitica.ui.fragments.BaseFragment
|
||||
import com.habitrpg.android.habitica.ui.viewmodels.BaseViewModel
|
||||
import javax.inject.Inject
|
||||
|
||||
class PartyInviteFragment : BaseFragment<FragmentPartyInviteBinding>() {
|
||||
class PartyInviteViewModel: BaseViewModel() {
|
||||
override fun inject(component : UserComponent) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class PartyInviteFragment : BaseFragment<FragmentComposeBinding>() {
|
||||
|
||||
@Inject
|
||||
lateinit var configManager: AppConfigManager
|
||||
|
||||
override var binding: FragmentPartyInviteBinding? = null
|
||||
override var binding: FragmentComposeBinding? = null
|
||||
|
||||
override fun createBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentPartyInviteBinding {
|
||||
return FragmentPartyInviteBinding.inflate(inflater, container, false)
|
||||
override fun createBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentComposeBinding {
|
||||
return FragmentComposeBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
var isEmailInvite: Boolean = false
|
||||
|
||||
val values: Array<String>
|
||||
get() {
|
||||
val values = ArrayList<String>()
|
||||
for (i in 0 until (binding?.invitationWrapper?.childCount ?: 0)) {
|
||||
val valueEditText = binding?.invitationWrapper?.getChildAt(i) as? EditText
|
||||
if (valueEditText?.text?.toString()?.isNotEmpty() == true) {
|
||||
values.add(valueEditText.text.toString())
|
||||
}
|
||||
}
|
||||
return values.toTypedArray()
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
if (isEmailInvite) {
|
||||
binding?.inviteDescription?.text = getString(R.string.invite_email_description)
|
||||
} else {
|
||||
binding?.inviteDescription?.text = getString(R.string.invite_username_description)
|
||||
}
|
||||
|
||||
addInviteField()
|
||||
|
||||
binding?.addInviteButton?.setOnClickListener { addInviteField() }
|
||||
}
|
||||
|
||||
override fun injectFragment(component: UserComponent) {
|
||||
component.inject(this)
|
||||
}
|
||||
|
||||
private fun addInviteField() {
|
||||
val editText = EditText(context)
|
||||
|
||||
if (isEmailInvite) {
|
||||
editText.setHint(R.string.email)
|
||||
editText.inputType = InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
|
||||
} else {
|
||||
editText.setHint(R.string.username)
|
||||
}
|
||||
binding?.invitationWrapper?.addView(editText)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
package com.habitrpg.android.habitica.ui.fragments.social.party
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.components.UserComponent
|
||||
import com.habitrpg.android.habitica.databinding.FragmentViewpagerBinding
|
||||
import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment
|
||||
|
||||
class PartyInvitePagerFragment : BaseMainFragment<FragmentViewpagerBinding>() {
|
||||
|
||||
override var binding : FragmentViewpagerBinding? = null
|
||||
|
||||
override fun createBinding(
|
||||
inflater : LayoutInflater,
|
||||
container : ViewGroup?
|
||||
) : FragmentViewpagerBinding {
|
||||
return FragmentViewpagerBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater : LayoutInflater,
|
||||
container : ViewGroup?,
|
||||
savedInstanceState : Bundle?
|
||||
) : View? {
|
||||
this.usesTabLayout = true
|
||||
this.hidesToolbar = true
|
||||
return super.onCreateView(inflater, container, savedInstanceState)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view : View, savedInstanceState : Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
setViewPagerAdapter()
|
||||
binding?.viewPager?.currentItem = 0
|
||||
}
|
||||
|
||||
override fun injectFragment(component : UserComponent) {
|
||||
component.inject(this)
|
||||
}
|
||||
|
||||
private fun setViewPagerAdapter() {
|
||||
val fragmentManager = childFragmentManager
|
||||
binding?.viewPager?.adapter = object : FragmentStateAdapter(fragmentManager, lifecycle) {
|
||||
override fun createFragment(position : Int) : Fragment {
|
||||
return when (position) {
|
||||
0 -> {
|
||||
PartySeekingFragment()
|
||||
}
|
||||
|
||||
1 -> {
|
||||
PartyInviteFragment()
|
||||
}
|
||||
|
||||
else -> Fragment()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount() : Int {
|
||||
return 2
|
||||
}
|
||||
}
|
||||
tabLayout?.let {
|
||||
binding?.viewPager?.let { it1 ->
|
||||
TabLayoutMediator(it, it1) { tab, position ->
|
||||
tab.text = when (position) {
|
||||
0 -> context?.getString(R.string.list)
|
||||
1 -> context?.getString(R.string.by_invite)
|
||||
else -> ""
|
||||
}
|
||||
}.attach()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
package com.habitrpg.android.habitica.ui.fragments.social.party
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.pullrefresh.pullRefresh
|
||||
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.components.UserComponent
|
||||
import com.habitrpg.android.habitica.data.SocialRepository
|
||||
import com.habitrpg.android.habitica.databinding.FragmentComposeBinding
|
||||
import com.habitrpg.android.habitica.models.members.Member
|
||||
import com.habitrpg.android.habitica.ui.fragments.BaseFragment
|
||||
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
|
||||
import com.habitrpg.android.habitica.ui.viewmodels.BaseViewModel
|
||||
import com.habitrpg.common.habitica.helpers.launchCatching
|
||||
import javax.inject.Inject
|
||||
|
||||
class PartySeekingViewModel: BaseViewModel() {
|
||||
val isRefreshing = mutableStateOf(false)
|
||||
|
||||
@Inject
|
||||
lateinit var socialRepository: SocialRepository
|
||||
|
||||
val seekingUsers = mutableStateOf<List<Member>>(emptyList())
|
||||
|
||||
override fun inject(component : UserComponent) {
|
||||
component.inject(this)
|
||||
}
|
||||
|
||||
init {
|
||||
retrieveUsers()
|
||||
}
|
||||
|
||||
fun retrieveUsers() {
|
||||
isRefreshing.value = true
|
||||
viewModelScope.launchCatching {
|
||||
seekingUsers.value = socialRepository.retrievePartySeekingUsers() ?: emptyList()
|
||||
isRefreshing.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PartySeekingFragment: BaseFragment<FragmentComposeBinding>() {
|
||||
val viewModel: PartySeekingViewModel by viewModels()
|
||||
|
||||
override var binding: FragmentComposeBinding? = null
|
||||
override fun createBinding(
|
||||
inflater : LayoutInflater,
|
||||
container : ViewGroup?
|
||||
) : FragmentComposeBinding {
|
||||
return FragmentComposeBinding.inflate(inflater)
|
||||
}
|
||||
|
||||
override fun injectFragment(component : UserComponent) {
|
||||
component.inject(this)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater : LayoutInflater,
|
||||
container : ViewGroup?,
|
||||
savedInstanceState : Bundle?
|
||||
) : View? {
|
||||
val view = super.onCreateView(inflater, container, savedInstanceState)
|
||||
binding?.composeView?.setContent {
|
||||
HabiticaTheme {
|
||||
PartySeekingView(viewModel)
|
||||
}
|
||||
}
|
||||
return view
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
viewModel.retrieveUsers()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun PartySeekingListItem(user: Member,
|
||||
modifier : Modifier = Modifier) {
|
||||
Column(modifier.fillMaxWidth()) {
|
||||
Text(user.username ?: "")
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
fun PartySeekingView(
|
||||
viewModel: PartySeekingViewModel,
|
||||
modifier : Modifier = Modifier
|
||||
) {
|
||||
val users: List<Member> by viewModel.seekingUsers
|
||||
val refreshing by viewModel.isRefreshing
|
||||
val pullRefreshState = rememberPullRefreshState(refreshing, { viewModel.retrieveUsers() })
|
||||
|
||||
LazyColumn(modifier.pullRefresh(pullRefreshState)) {
|
||||
item {
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.fillMaxWidth().padding(top = 22.dp, bottom = 14.dp)) {
|
||||
Text(stringResource(R.string.find_more_members), color = HabiticaTheme.colors.textPrimary, fontSize = 16.sp, fontWeight = FontWeight.Medium)
|
||||
Text(stringResource(R.string.habiticans_looking_party), color = HabiticaTheme.colors.textSecondary)
|
||||
}
|
||||
}
|
||||
items(users) {
|
||||
PartySeekingListItem(user = it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -31,7 +31,7 @@ class HostConfig {
|
|||
}
|
||||
} else {
|
||||
val address = sharedPreferences.getString("server_url", null)
|
||||
if (address != null && address.isNotEmpty()) {
|
||||
if (!address.isNullOrEmpty()) {
|
||||
this.address = address
|
||||
} else {
|
||||
this.address = context.getString(com.habitrpg.common.habitica.R.string.base_url)
|
||||
|
|
|
|||
Loading…
Reference in a new issue