diff --git a/app/src/fdroid/java/org/futo/circles/notifications/test/NotificationsBackgroundRestrictionsTest.kt b/app/src/fdroid/java/org/futo/circles/notifications/test/NotificationsBackgroundRestrictionsTest.kt index 6196b8582aaf176ec17cd7ee5c1fb78d0b92d09b..555ab446f4bc5e907beb2c533435782ad7070556 100644 --- a/app/src/fdroid/java/org/futo/circles/notifications/test/NotificationsBackgroundRestrictionsTest.kt +++ b/app/src/fdroid/java/org/futo/circles/notifications/test/NotificationsBackgroundRestrictionsTest.kt @@ -6,8 +6,8 @@ import androidx.core.content.getSystemService import androidx.core.net.ConnectivityManagerCompat import dagger.hilt.android.qualifiers.ApplicationContext import org.futo.circles.R +import org.futo.circles.core.model.TaskStatus import org.futo.circles.feature.notifications.test.task.BaseNotificationTest -import org.futo.circles.model.NotificationTestStatus import javax.inject.Inject class NotificationsBackgroundRestrictionsTest @Inject constructor( @@ -23,7 +23,7 @@ class NotificationsBackgroundRestrictionsTest @Inject constructor( R.string.settings_troubleshoot_test_bg_restricted_failed, "RESTRICT_BACKGROUND_STATUS_ENABLED" ) - status = NotificationTestStatus.FAILED + status = TaskStatus.FAILED quickFix = null } @@ -32,7 +32,7 @@ class NotificationsBackgroundRestrictionsTest @Inject constructor( R.string.settings_troubleshoot_test_bg_restricted_success, "RESTRICT_BACKGROUND_STATUS_WHITELISTED" ) - status = NotificationTestStatus.SUCCESS + status = TaskStatus.SUCCESS quickFix = null } @@ -41,7 +41,7 @@ class NotificationsBackgroundRestrictionsTest @Inject constructor( R.string.settings_troubleshoot_test_bg_restricted_success, "RESTRICT_BACKGROUND_STATUS_DISABLED" ) - status = NotificationTestStatus.SUCCESS + status = TaskStatus.SUCCESS quickFix = null } } @@ -50,7 +50,7 @@ class NotificationsBackgroundRestrictionsTest @Inject constructor( R.string.settings_troubleshoot_test_bg_restricted_success, "" ) - status = NotificationTestStatus.SUCCESS + status = TaskStatus.SUCCESS quickFix = null } } diff --git a/app/src/gplay/java/org/futo/circles/notifications/test/NotificationTestTokenRegistration.kt b/app/src/gplay/java/org/futo/circles/notifications/test/NotificationTestTokenRegistration.kt index c1f865524e1011c9e89b93ad3862a25da71d19a5..8200414359039dac25cf8c15ac7b8e32c0a37986 100644 --- a/app/src/gplay/java/org/futo/circles/notifications/test/NotificationTestTokenRegistration.kt +++ b/app/src/gplay/java/org/futo/circles/notifications/test/NotificationTestTokenRegistration.kt @@ -3,10 +3,10 @@ package org.futo.circles.notifications.test import android.content.Context import dagger.hilt.android.qualifiers.ApplicationContext import org.futo.circles.R +import org.futo.circles.core.model.TaskStatus import org.futo.circles.core.provider.MatrixSessionProvider import org.futo.circles.feature.notifications.FcmHelper import org.futo.circles.feature.notifications.test.task.BaseNotificationTest -import org.futo.circles.model.NotificationTestStatus import org.matrix.android.sdk.api.session.pushers.PusherState import javax.inject.Inject @@ -17,11 +17,11 @@ class NotificationTestTokenRegistration @Inject constructor( override fun perform() { val fcmToken = fcmHelper.getFcmToken() ?: run { - status = NotificationTestStatus.FAILED + status = TaskStatus.FAILED return } val session = MatrixSessionProvider.currentSession ?: run { - status = NotificationTestStatus.FAILED + status = TaskStatus.FAILED return } val pushers = session.pushersService().getPushers().filter { @@ -32,11 +32,11 @@ class NotificationTestTokenRegistration @Inject constructor( R.string.settings_troubleshoot_test_token_registration_failed, context.getString(R.string.unexpected_error) ) - status = NotificationTestStatus.FAILED + status = TaskStatus.FAILED } else { description = context.getString(R.string.settings_troubleshoot_test_token_registration_success) - status = NotificationTestStatus.SUCCESS + status = TaskStatus.SUCCESS } } } diff --git a/app/src/gplay/java/org/futo/circles/notifications/test/NotificationsTestFirebaseToken.kt b/app/src/gplay/java/org/futo/circles/notifications/test/NotificationsTestFirebaseToken.kt index e2d6c8fb372efa8c5f2512ebcd2fdd6749746ea3..801d3c6fc5fb8db4ff7b50f6e33e2327308e3d7d 100644 --- a/app/src/gplay/java/org/futo/circles/notifications/test/NotificationsTestFirebaseToken.kt +++ b/app/src/gplay/java/org/futo/circles/notifications/test/NotificationsTestFirebaseToken.kt @@ -4,9 +4,9 @@ import android.content.Context import com.google.firebase.messaging.FirebaseMessaging import dagger.hilt.android.qualifiers.ApplicationContext import org.futo.circles.R +import org.futo.circles.core.model.TaskStatus import org.futo.circles.feature.notifications.FcmHelper import org.futo.circles.feature.notifications.test.task.BaseNotificationTest -import org.futo.circles.model.NotificationTestStatus import javax.inject.Inject class NotificationsTestFirebaseToken @Inject constructor( @@ -19,7 +19,7 @@ class NotificationsTestFirebaseToken @Inject constructor( FirebaseMessaging.getInstance().token.addOnCompleteListener { task -> if (!task.isSuccessful) { description = task.exception?.localizedMessage ?: "Unknown" - status = NotificationTestStatus.FAILED + status = TaskStatus.FAILED } else { task.result?.let { token -> val tok = token.take(8) + "********************" @@ -29,7 +29,7 @@ class NotificationsTestFirebaseToken @Inject constructor( ) fcmHelper.storeFcmToken(token) } - status = NotificationTestStatus.SUCCESS + status = TaskStatus.SUCCESS } updateTestInfo() } @@ -38,7 +38,7 @@ class NotificationsTestFirebaseToken @Inject constructor( R.string.settings_troubleshoot_test_fcm_failed, e.localizedMessage ) - status = NotificationTestStatus.FAILED + status = TaskStatus.FAILED updateTestInfo() } } diff --git a/app/src/gplay/java/org/futo/circles/notifications/test/NotificationsTestPlayServices.kt b/app/src/gplay/java/org/futo/circles/notifications/test/NotificationsTestPlayServices.kt index 30c84cd30553c6baba689a7b9bdbb893bde6e2ae..b77e8aa343f1bc60f4124595ffc16ad1b6ac4f02 100644 --- a/app/src/gplay/java/org/futo/circles/notifications/test/NotificationsTestPlayServices.kt +++ b/app/src/gplay/java/org/futo/circles/notifications/test/NotificationsTestPlayServices.kt @@ -5,8 +5,8 @@ import com.google.android.gms.common.ConnectionResult import com.google.android.gms.common.GoogleApiAvailability import dagger.hilt.android.qualifiers.ApplicationContext import org.futo.circles.R +import org.futo.circles.core.model.TaskStatus import org.futo.circles.feature.notifications.test.task.BaseNotificationTest -import org.futo.circles.model.NotificationTestStatus import javax.inject.Inject class NotificationsTestPlayServices @Inject constructor( @@ -20,13 +20,13 @@ class NotificationsTestPlayServices @Inject constructor( quickFix = null description = context.getString(R.string.settings_troubleshoot_test_play_services_success) - status = NotificationTestStatus.SUCCESS + status = TaskStatus.SUCCESS } else { description = context.getString( R.string.settings_troubleshoot_test_play_services_failed, apiAvailability.getErrorString(resultCode) ) - status = NotificationTestStatus.FAILED + status = TaskStatus.FAILED } } } diff --git a/app/src/main/java/org/futo/circles/feature/circles/CirclesDataSource.kt b/app/src/main/java/org/futo/circles/feature/circles/CirclesDataSource.kt index 98957d7791a1ebfe131ff5c22bdeccb038748cb3..c563754a068a311f3ecd035c53e81ee166d6c58c 100644 --- a/app/src/main/java/org/futo/circles/feature/circles/CirclesDataSource.kt +++ b/app/src/main/java/org/futo/circles/feature/circles/CirclesDataSource.kt @@ -5,14 +5,15 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.withContext -import org.futo.circles.core.extensions.createResult import org.futo.circles.core.mapping.toRoomInfo -import org.futo.circles.core.model.CIRCLE_TAG +import org.futo.circles.core.model.CIRCLES_SPACE_ACCOUNT_DATA_KEY import org.futo.circles.core.model.TIMELINE_TYPE import org.futo.circles.core.provider.MatrixSessionProvider import org.futo.circles.core.utils.UserUtils +import org.futo.circles.core.utils.getJoinedRoomById import org.futo.circles.core.utils.getTimelineRoomFor -import org.futo.circles.core.utils.isCircleShared +import org.futo.circles.core.workspace.SharedCircleDataSource +import org.futo.circles.core.workspace.SpacesTreeAccountDataSource import org.futo.circles.mapping.toInviteCircleListItem import org.futo.circles.mapping.toJoinedCircleListItem import org.futo.circles.model.CircleListItem @@ -24,7 +25,10 @@ import org.matrix.android.sdk.api.session.room.model.RoomSummary import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams import javax.inject.Inject -class CirclesDataSource @Inject constructor() { +class CirclesDataSource @Inject constructor( + private val spacesTreeAccountDataSource: SpacesTreeAccountDataSource, + private val sharedCircleDataSource: SharedCircleDataSource +) { fun getCirclesFlow() = combine( MatrixSessionProvider.getSessionOrThrow().roomService() @@ -40,7 +44,9 @@ class CirclesDataSource @Inject constructor() { list.filter { isInviteToCircleTimeline(it) }.map { it.toInviteCircleListItem() } val joinedCircles = list.filter { isJoinedCircle(it) } val sharedCircles = - joinedCircles.filter { joinedCircle -> isCircleShared(joinedCircle.roomId) } + joinedCircles.filter { joinedCircle -> + sharedCircleDataSource.isCircleShared(joinedCircle.roomId) + } val privateCircles = joinedCircles - sharedCircles.toSet() val requests = getKnockRequestToSharedTimelines(joinedCircles) @@ -57,8 +63,14 @@ class CirclesDataSource @Inject constructor() { return displayList } - private fun isJoinedCircle(summary: RoomSummary) = - summary.hasTag(CIRCLE_TAG) && summary.membership == Membership.JOIN + fun isJoinedCircle(summary: RoomSummary): Boolean { + if (summary.roomId == sharedCircleDataSource.getSharedCirclesSpaceId()) return false + val circlesSpaceId = spacesTreeAccountDataSource.getRoomIdByKey( + CIRCLES_SPACE_ACCOUNT_DATA_KEY + ) ?: return false + return getJoinedRoomById(circlesSpaceId)?.roomSummary()?.spaceChildren?.map { it.childRoomId } + ?.contains(summary.roomId) == true + } private fun isInviteToCircleTimeline(summary: RoomSummary) = summary.roomType == TIMELINE_TYPE && summary.membership == Membership.INVITE diff --git a/app/src/main/java/org/futo/circles/feature/circles/CirclesViewModel.kt b/app/src/main/java/org/futo/circles/feature/circles/CirclesViewModel.kt index ad2e5dc0dd6018f3a8c50cc41f6007f2e022ad39..68fb17e3917ece6938365122292b1541ce1b52a6 100644 --- a/app/src/main/java/org/futo/circles/feature/circles/CirclesViewModel.kt +++ b/app/src/main/java/org/futo/circles/feature/circles/CirclesViewModel.kt @@ -53,9 +53,7 @@ class CirclesViewModel @Inject constructor( launchBg { val result = createResult { if (getTimelineRoomFor(circleId) == null) { - createTimelineLoadingLiveData.postValue( - LoadingData(R.string.creating_timeline, total = 0) - ) + createTimelineLoadingLiveData.postValue(LoadingData(R.string.creating_timeline)) val name = MatrixSessionProvider.getSessionOrThrow().getRoomSummary(circleId)?.name createRoomDataSource.createCircleTimeline(circleId, name) diff --git a/app/src/main/java/org/futo/circles/feature/circles/accept_invite/AcceptCircleInviteDataSource.kt b/app/src/main/java/org/futo/circles/feature/circles/accept_invite/AcceptCircleInviteDataSource.kt index 301c7872e0f78e9ec268588d1e4176c715f2f6b4..1a5baa16d458602cc68e0eefd6b42df09a0864f0 100644 --- a/app/src/main/java/org/futo/circles/feature/circles/accept_invite/AcceptCircleInviteDataSource.kt +++ b/app/src/main/java/org/futo/circles/feature/circles/accept_invite/AcceptCircleInviteDataSource.kt @@ -22,7 +22,7 @@ class AcceptCircleInviteDataSource @Inject constructor( suspend fun acceptCircleInvite(selectedCircles: List<SelectableRoomListItem>) = createResult { session?.roomService()?.joinRoom(roomId) selectedCircles.forEach { circle -> - roomRelationsBuilder.setInvitedCircleRelations(roomId, circle.id) + roomRelationsBuilder.setInvitedRoomRelations(roomId, circle.id) } } diff --git a/app/src/main/java/org/futo/circles/feature/circles/setup/SetupCirclesDataSource.kt b/app/src/main/java/org/futo/circles/feature/circles/setup/SetupCirclesDataSource.kt deleted file mode 100644 index 15695a2438ce3405987fef23a33e9c82e50b64cd..0000000000000000000000000000000000000000 --- a/app/src/main/java/org/futo/circles/feature/circles/setup/SetupCirclesDataSource.kt +++ /dev/null @@ -1,42 +0,0 @@ -package org.futo.circles.feature.circles.setup - -import android.content.Context -import android.net.Uri -import androidx.lifecycle.MutableLiveData -import dagger.hilt.android.qualifiers.ApplicationContext -import org.futo.circles.R -import org.futo.circles.core.extensions.notEmptyDisplayName -import org.futo.circles.core.provider.MatrixSessionProvider -import org.futo.circles.model.SetupCircleListItem -import org.matrix.android.sdk.api.session.getUser -import javax.inject.Inject - -class SetupCirclesDataSource @Inject constructor( - @ApplicationContext private val context: Context -) { - - val circlesLiveData = MutableLiveData(getInitialCirclesList()) - - private fun getInitialCirclesList(): List<SetupCircleListItem> = - context.resources.getStringArray(R.array.setup_circles_list).mapIndexed { i, name -> - SetupCircleListItem( - id = i, - name = name, - userName = getUserName() - ) - } - - private fun getUserName(): String { - val session = MatrixSessionProvider.currentSession - val userId = session?.myUserId ?: return "" - return session.getUser(userId)?.notEmptyDisplayName() ?: "" - } - - fun addCirclesCoverImage(id: Int, uri: Uri) { - val list = circlesLiveData.value?.map { - if (it.id == id) it.copy(coverUri = uri) else it - } ?: emptyList() - - circlesLiveData.postValue(list) - } -} \ No newline at end of file diff --git a/app/src/main/java/org/futo/circles/feature/circles/setup/SetupCirclesFragment.kt b/app/src/main/java/org/futo/circles/feature/circles/setup/SetupCirclesFragment.kt deleted file mode 100644 index dc62708b987819aa51e7900f610b736573669677..0000000000000000000000000000000000000000 --- a/app/src/main/java/org/futo/circles/feature/circles/setup/SetupCirclesFragment.kt +++ /dev/null @@ -1,96 +0,0 @@ -package org.futo.circles.feature.circles.setup - -import android.os.Bundle -import android.view.View -import androidx.fragment.app.Fragment -import androidx.fragment.app.viewModels -import androidx.navigation.fragment.findNavController -import androidx.recyclerview.widget.DividerItemDecoration -import by.kirich1409.viewbindingdelegate.viewBinding -import dagger.hilt.android.AndroidEntryPoint -import org.futo.circles.R -import org.futo.circles.core.extensions.navigateSafe -import org.futo.circles.core.extensions.observeData -import org.futo.circles.core.extensions.observeResponse -import org.futo.circles.core.extensions.showError -import org.futo.circles.core.extensions.showSuccess -import org.futo.circles.core.fragment.HasLoadingState -import org.futo.circles.core.model.LoadingData -import org.futo.circles.core.picker.helper.MediaPickerHelper -import org.futo.circles.core.view.LoadingDialog -import org.futo.circles.databinding.FragmentSetupCirclesBinding -import org.futo.circles.feature.circles.setup.list.SetupCirclesAdapter -import org.futo.circles.model.SetupCircleListItem - -@AndroidEntryPoint -class SetupCirclesFragment : Fragment(R.layout.fragment_setup_circles), HasLoadingState { - - override val fragment: Fragment = this - private val viewModel by viewModels<SetupCirclesViewModel>() - private val binding by viewBinding(FragmentSetupCirclesBinding::bind) - private val listAdapter by lazy { SetupCirclesAdapter(::onCircleListItemClicked) } - private val mediaPickerHelper = MediaPickerHelper(this, isGalleryAvailable = false) - private val loadingDialog by lazy { LoadingDialog(requireContext()) } - - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - setupViews() - setupObservers() - } - - private fun setupViews() { - with(binding) { - rvSetupCircles.apply { - addItemDecoration(DividerItemDecoration(context, DividerItemDecoration.VERTICAL)) - adapter = listAdapter - } - btnSkip.setOnClickListener { navigateToBottomMenuScreen() } - btnSave.setOnClickListener { - showLoading() - viewModel.createCircles() - } - } - } - - private fun setupObservers() { - viewModel.circlesLiveData.observeData(this, ::setCirclesList) - viewModel.createCirclesResponseLiveData.observeResponse(this, - success = { - loadingDialog.dismiss() - showSuccess(getString(R.string.circles_created)) - navigateToBottomMenuScreen() - }, - error = { - showError(it) - loadingDialog.dismiss() - } - ) - } - - private fun setCirclesList(list: List<SetupCircleListItem>) { - listAdapter.submitList(list) - } - - private fun onCircleListItemClicked(circle: SetupCircleListItem) { - mediaPickerHelper.showMediaPickerDialog( - onImageSelected = { id, uri -> viewModel.addImageForCircle(id, uri) }, - id = circle.id - ) - } - - private fun showLoading() { - startLoading(binding.btnSave) - loadingDialog.handleLoading( - LoadingData( - total = 0, - messageId = R.string.configuring_workspace, - isLoading = true - ) - ) - } - - private fun navigateToBottomMenuScreen() { - findNavController().navigateSafe(SetupCirclesFragmentDirections.toHomeFragment()) - } -} \ No newline at end of file diff --git a/app/src/main/java/org/futo/circles/feature/circles/setup/SetupCirclesViewModel.kt b/app/src/main/java/org/futo/circles/feature/circles/setup/SetupCirclesViewModel.kt deleted file mode 100644 index c9675b1694f2996d79cd123b08eacbcb8c554aaa..0000000000000000000000000000000000000000 --- a/app/src/main/java/org/futo/circles/feature/circles/setup/SetupCirclesViewModel.kt +++ /dev/null @@ -1,45 +0,0 @@ -package org.futo.circles.feature.circles.setup - -import android.net.Uri -import androidx.lifecycle.ViewModel -import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.delay -import org.futo.circles.core.CREATE_ROOM_DELAY -import org.futo.circles.core.SingleEventLiveData -import org.futo.circles.core.extensions.Response -import org.futo.circles.core.extensions.createResult -import org.futo.circles.core.extensions.launchBg -import org.futo.circles.core.room.CreateRoomDataSource -import javax.inject.Inject - -@HiltViewModel -class SetupCirclesViewModel @Inject constructor( - private val setupCirclesDataSource: SetupCirclesDataSource, - private val createRoomDataSource: CreateRoomDataSource -) : ViewModel() { - - val circlesLiveData = setupCirclesDataSource.circlesLiveData - val createCirclesResponseLiveData = SingleEventLiveData<Response<Unit?>>() - - fun createCircles() { - val circlesList = circlesLiveData.value ?: return - val lastItemIndex = circlesList.size - 1 - launchBg { - val response = createResult { - circlesList.forEachIndexed { i, item -> - createRoomDataSource.createCircleWithTimeline( - name = item.name, - iconUri = item.coverUri, - null, false - ) - if (i != lastItemIndex) delay(CREATE_ROOM_DELAY) - } - } - createCirclesResponseLiveData.postValue(response) - } - } - - fun addImageForCircle(id: Int?, uri: Uri) { - id?.let { setupCirclesDataSource.addCirclesCoverImage(it, uri) } - } -} \ No newline at end of file diff --git a/app/src/main/java/org/futo/circles/feature/circles/setup/list/SetupCirclesAdapter.kt b/app/src/main/java/org/futo/circles/feature/circles/setup/list/SetupCirclesAdapter.kt deleted file mode 100644 index 661baab8d99773d8ef4decf0f88efa3e62b7bc0d..0000000000000000000000000000000000000000 --- a/app/src/main/java/org/futo/circles/feature/circles/setup/list/SetupCirclesAdapter.kt +++ /dev/null @@ -1,23 +0,0 @@ -package org.futo.circles.feature.circles.setup.list - - -import android.view.ViewGroup -import org.futo.circles.core.list.BaseRvAdapter -import org.futo.circles.model.SetupCircleListItem - -class SetupCirclesAdapter( - private val onCircleClicked: (SetupCircleListItem) -> Unit -) : BaseRvAdapter<SetupCircleListItem, SetupCirclesViewHolder>(DefaultIdEntityCallback()) { - - override fun onCreateViewHolder( - parent: ViewGroup, - viewType: Int - ): SetupCirclesViewHolder = SetupCirclesViewHolder( - parent = parent, - onCircleClicked = { position -> onCircleClicked(getItem(position)) } - ) - - override fun onBindViewHolder(holder: SetupCirclesViewHolder, position: Int) { - holder.bind(getItem(position)) - } -} \ No newline at end of file diff --git a/app/src/main/java/org/futo/circles/feature/circles/setup/list/SetupCirclesViewHolder.kt b/app/src/main/java/org/futo/circles/feature/circles/setup/list/SetupCirclesViewHolder.kt deleted file mode 100644 index d290d4a1d05de311360020a5971c18cfdf227b5a..0000000000000000000000000000000000000000 --- a/app/src/main/java/org/futo/circles/feature/circles/setup/list/SetupCirclesViewHolder.kt +++ /dev/null @@ -1,33 +0,0 @@ -package org.futo.circles.feature.circles.setup.list - -import android.view.ViewGroup -import androidx.recyclerview.widget.RecyclerView -import org.futo.circles.R -import org.futo.circles.core.extensions.onClick -import org.futo.circles.core.list.ViewBindingHolder -import org.futo.circles.databinding.ListItemSetupCircleBinding -import org.futo.circles.model.SetupCircleListItem - -class SetupCirclesViewHolder( - parent: ViewGroup, - onCircleClicked: (Int) -> Unit -) : RecyclerView.ViewHolder(inflate(parent, ListItemSetupCircleBinding::inflate)) { - - private companion object : ViewBindingHolder - - private val binding = baseBinding as ListItemSetupCircleBinding - - init { - onClick(itemView) { position -> onCircleClicked(position) } - } - - fun bind(data: SetupCircleListItem) { - with(binding) { - data.coverUri?.let { ivCircleCover.setImageURI(it) } - ?: ivCircleCover.setImageResource(R.drawable.add_image_placeholder) - - tvCircleName.text = data.name - tvUserName.text = data.userName - } - } -} \ No newline at end of file diff --git a/app/src/main/java/org/futo/circles/feature/home/HomeFragment.kt b/app/src/main/java/org/futo/circles/feature/home/HomeFragment.kt index afc90db1a750107d37f60753668e31a2f29474fa..66f853d2c27a720611e53b3ed36408876e21c867 100644 --- a/app/src/main/java/org/futo/circles/feature/home/HomeFragment.kt +++ b/app/src/main/java/org/futo/circles/feature/home/HomeFragment.kt @@ -18,19 +18,22 @@ import by.kirich1409.viewbindingdelegate.viewBinding import dagger.hilt.android.AndroidEntryPoint import org.futo.circles.MainActivity import org.futo.circles.R +import org.futo.circles.auth.feature.workspace.WorkspaceDialogFragment import org.futo.circles.core.SHARE_PROFILE_URL_PREFIX import org.futo.circles.core.SHARE_ROOM_URL_PREFIX import org.futo.circles.core.extensions.navigateSafe import org.futo.circles.core.extensions.observeData +import org.futo.circles.core.extensions.observeResponse import org.futo.circles.core.extensions.setSupportActionBar import org.futo.circles.core.model.CircleRoomTypeArg import org.futo.circles.core.model.GROUP_TYPE +import org.futo.circles.core.model.LoadingData import org.futo.circles.core.model.TIMELINE_TYPE import org.futo.circles.core.picker.helper.RuntimePermissionHelper import org.futo.circles.core.provider.MatrixSessionProvider +import org.futo.circles.core.view.LoadingDialog import org.futo.circles.databinding.FragmentBottomNavigationBinding import org.futo.circles.gallery.feature.backup.service.MediaBackupServiceManager -import org.futo.circles.core.notices.SystemNoticesCountSharedViewModel import org.matrix.android.sdk.api.session.getRoomSummary import javax.inject.Inject @@ -48,7 +51,7 @@ class HomeFragment : Fragment(R.layout.fragment_bottom_navigation), DeepLinkInte RuntimePermissionHelper(this, Manifest.permission.POST_NOTIFICATIONS) private val viewModel by viewModels<HomeViewModel>() - private val systemNoticesCountViewModel by activityViewModels<SystemNoticesCountSharedViewModel>() + private val loadingDialog by lazy { LoadingDialog(requireContext()) } @Inject lateinit var mediaBackupServiceManager: MediaBackupServiceManager @@ -59,6 +62,7 @@ class HomeFragment : Fragment(R.layout.fragment_bottom_navigation), DeepLinkInte binding.bottomNavigationView.setupWithNavController(controller) setupToolBar(controller) } + loadingDialog.handleLoading(LoadingData(org.futo.circles.auth.R.string.validating_workspace)) setupObservers() registerPushNotifications() handleDeepLinks() @@ -112,19 +116,15 @@ class HomeFragment : Fragment(R.layout.fragment_bottom_navigation), DeepLinkInte } private fun setupObservers() { - systemNoticesCountViewModel.systemNoticesCountLiveData?.observeData(this) { - val count = it ?: 0 - binding.bottomNavigationView.getOrCreateBadge(R.id.settings_nav_graph).apply { - isVisible = count > 0 - number = count - } - } viewModel.inviteIntoSharedSpaceLiveData?.observeData(this) { viewModel.autoAcceptInviteOnKnock(it) } viewModel.mediaBackupSettingsLiveData?.observeData(this) { mediaBackupServiceManager.bindMediaServiceIfNeeded(requireContext(), it) } + viewModel.validateWorkspaceResultLiveData.observeResponse(this, + error = { WorkspaceDialogFragment().show(childFragmentManager, "workspace") }, + onRequestInvoked = { loadingDialog.dismiss() }) } private fun registerPushNotifications() { diff --git a/app/src/main/java/org/futo/circles/feature/home/HomeViewModel.kt b/app/src/main/java/org/futo/circles/feature/home/HomeViewModel.kt index 7cd83d21d5469bc6e7309bc67f5f6c93bc17911b..a8fcde94838226bdd1158789548dc31a4f8951aa 100644 --- a/app/src/main/java/org/futo/circles/feature/home/HomeViewModel.kt +++ b/app/src/main/java/org/futo/circles/feature/home/HomeViewModel.kt @@ -4,13 +4,14 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.map import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel +import org.futo.circles.auth.feature.workspace.data_source.ConfigureWorkspaceDataSource +import org.futo.circles.auth.feature.workspace.data_source.WorkspaceTasksProvider +import org.futo.circles.core.SingleEventLiveData +import org.futo.circles.core.extensions.Response +import org.futo.circles.core.extensions.createResult import org.futo.circles.core.extensions.launchBg -import org.futo.circles.core.model.CIRCLE_TAG import org.futo.circles.core.model.GROUP_TYPE -import org.futo.circles.core.model.SharedCirclesSpace import org.futo.circles.core.provider.MatrixSessionProvider -import org.futo.circles.core.room.CreateRoomDataSource -import org.futo.circles.core.utils.getSharedCirclesSpaceId import org.futo.circles.feature.notifications.PushersManager import org.futo.circles.feature.notifications.ShortcutsHandler import org.futo.circles.gallery.feature.backup.RoomAccountDataSource @@ -23,11 +24,13 @@ import javax.inject.Inject @HiltViewModel class HomeViewModel @Inject constructor( private val pushersManager: PushersManager, - private val createRoomDataSource: CreateRoomDataSource, + private val workspaceTasksProvider: WorkspaceTasksProvider, + private val workspaceDataSource: ConfigureWorkspaceDataSource, roomAccountDataSource: RoomAccountDataSource, shortcutsHandler: ShortcutsHandler ) : ViewModel() { + val validateWorkspaceResultLiveData = SingleEventLiveData<Response<Unit>>() val mediaBackupSettingsLiveData = roomAccountDataSource.getMediaBackupSettingsLive() val inviteIntoSharedSpaceLiveData = MatrixSessionProvider.currentSession?.roomService() ?.getRoomSummariesLive(roomSummaryQueryParams { @@ -37,14 +40,22 @@ class HomeViewModel @Inject constructor( init { shortcutsHandler.observeRoomsAndBuildShortcuts(viewModelScope) - createSharedCirclesSpaceIfNotExist() + validateWorkspace() } - private fun createSharedCirclesSpaceIfNotExist() { - if (getSharedCirclesSpaceId() != null) return - launchBg { createRoomDataSource.createRoom(SharedCirclesSpace()) } + private fun validateWorkspace() = launchBg { + val tasks = workspaceTasksProvider.getMandatoryTasks() + tasks.forEach { item -> + val validationResponse = createResult { workspaceDataSource.validate(item.room) } + (validationResponse as? Response.Error)?.let { + validateWorkspaceResultLiveData.postValue(Response.Error("")) + return@launchBg + } + } + validateWorkspaceResultLiveData.postValue(Response.Success(Unit)) } + fun registerPushNotifications() { pushersManager.registerPushNotifications() } @@ -56,16 +67,10 @@ class HomeViewModel @Inject constructor( } - private fun getParentSpaceIdForRoom(summary: RoomSummary): String? { - val circles = MatrixSessionProvider.currentSession?.roomService() - ?.getRoomSummaries(roomSummaryQueryParams { excludeType = null }) - ?.filter { item -> item.hasTag(CIRCLE_TAG) } ?: emptyList() + private fun getParentSpaceIdForRoom(summary: RoomSummary): String? = + summary.spaceParents?.firstOrNull { it.roomSummary?.membership == Membership.JOIN } + ?.roomSummary?.roomId - val parentCircle = - circles.firstOrNull { it.spaceChildren?.firstOrNull { it.childRoomId == summary.roomId } != null } - - return parentCircle?.roomId - } fun autoAcceptInviteOnKnock(roomIds: List<String>) { MatrixSessionProvider.currentSession?.let { session -> diff --git a/app/src/main/java/org/futo/circles/feature/notifications/test/list/NotificationTestViewHolder.kt b/app/src/main/java/org/futo/circles/feature/notifications/test/list/NotificationTestViewHolder.kt index a219f65bcecb9071bfc16c563d6c579d912fc66c..52ab4690dcb542dd39fda88a803b87853444b58f 100644 --- a/app/src/main/java/org/futo/circles/feature/notifications/test/list/NotificationTestViewHolder.kt +++ b/app/src/main/java/org/futo/circles/feature/notifications/test/list/NotificationTestViewHolder.kt @@ -9,9 +9,9 @@ import org.futo.circles.core.extensions.setIsVisible import org.futo.circles.core.extensions.visible import org.futo.circles.core.list.ViewBindingHolder import org.futo.circles.core.list.context +import org.futo.circles.core.model.TaskStatus import org.futo.circles.databinding.ListItemNotificationTestBinding import org.futo.circles.model.NotificationTestListItem -import org.futo.circles.model.NotificationTestStatus class NotificationTestViewHolder( parent: ViewGroup, @@ -32,12 +32,12 @@ class NotificationTestViewHolder( tvMessage.text = data.message btnFix.setIsVisible(data.hasFix) when (data.status) { - NotificationTestStatus.RUNNING -> { + TaskStatus.RUNNING -> { ivTestStatus.gone() testProgress.visible() } - NotificationTestStatus.IDLE -> { + TaskStatus.IDLE -> { ivTestStatus.gone() testProgress.gone() } @@ -46,7 +46,7 @@ class NotificationTestViewHolder( ivTestStatus.visible() testProgress.gone() ivTestStatus.setImageResource( - if (data.status == NotificationTestStatus.FAILED) R.drawable.ic_error + if (data.status == TaskStatus.FAILED) R.drawable.ic_error else R.drawable.ic_check_circle ) } diff --git a/app/src/main/java/org/futo/circles/feature/notifications/test/list/NotificationsTestAdapter.kt b/app/src/main/java/org/futo/circles/feature/notifications/test/list/NotificationsTestAdapter.kt index 8fce20c40f0023af793b4c937f61c6dfa39cabec..a6d940ce95a0a4b1b29ad682172d745f1e4f9cc7 100644 --- a/app/src/main/java/org/futo/circles/feature/notifications/test/list/NotificationsTestAdapter.kt +++ b/app/src/main/java/org/futo/circles/feature/notifications/test/list/NotificationsTestAdapter.kt @@ -6,8 +6,7 @@ import org.futo.circles.model.NotificationTestListItem class NotificationsTestAdapter( private val onFixClicked: (Int) -> Unit, -) : - BaseRvAdapter<NotificationTestListItem, NotificationTestViewHolder>(DefaultIdEntityCallback()) { +) : BaseRvAdapter<NotificationTestListItem, NotificationTestViewHolder>(DefaultIdEntityCallback()) { override fun onCreateViewHolder( parent: ViewGroup, diff --git a/app/src/main/java/org/futo/circles/feature/notifications/test/task/BaseNotificationTest.kt b/app/src/main/java/org/futo/circles/feature/notifications/test/task/BaseNotificationTest.kt index 20abd59406c25e871340a5f057aafefe139ace10..460e738180d16a94fe0ea1c5e46d7e12ca5334f1 100644 --- a/app/src/main/java/org/futo/circles/feature/notifications/test/task/BaseNotificationTest.kt +++ b/app/src/main/java/org/futo/circles/feature/notifications/test/task/BaseNotificationTest.kt @@ -1,20 +1,20 @@ package org.futo.circles.feature.notifications.test.task import androidx.annotation.StringRes +import org.futo.circles.core.model.TaskStatus import org.futo.circles.model.NotificationTestListItem -import org.futo.circles.model.NotificationTestStatus abstract class BaseNotificationTest(@StringRes val titleResId: Int) { protected var description: String = "" protected var quickFix: NotificationQuickFix? = null - protected var status: NotificationTestStatus = NotificationTestStatus.IDLE + protected var status: TaskStatus = TaskStatus.IDLE protected abstract fun perform() private var onTestUpdateListener: ((NotificationTestListItem) -> Unit)? = null fun runTest(updateListener: (NotificationTestListItem) -> Unit) { onTestUpdateListener = updateListener - status = NotificationTestStatus.RUNNING + status = TaskStatus.RUNNING description = "" quickFix = null updateTestInfo() @@ -23,7 +23,7 @@ abstract class BaseNotificationTest(@StringRes val titleResId: Int) { } fun runFix() { - status = NotificationTestStatus.RUNNING + status = TaskStatus.RUNNING description = "" quickFix = null updateTestInfo() diff --git a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationAccountSettingsTest.kt b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationAccountSettingsTest.kt index 42c072dc646680d6959a3806bf5542bf56da23df..f596fc2df553aa377e95b47a98ae71177f02a817 100644 --- a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationAccountSettingsTest.kt +++ b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationAccountSettingsTest.kt @@ -7,8 +7,8 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.futo.circles.R import org.futo.circles.core.extensions.coroutineScope +import org.futo.circles.core.model.TaskStatus import org.futo.circles.core.provider.MatrixSessionProvider -import org.futo.circles.model.NotificationTestStatus import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.session.pushrules.RuleIds import org.matrix.android.sdk.api.session.pushrules.RuleKind @@ -27,7 +27,7 @@ class NotificationAccountSettingsTest @Inject constructor(@ApplicationContext pr description = context.getString(R.string.settings_troubleshoot_test_account_settings_success) quickFix = null - status = NotificationTestStatus.SUCCESS + status = TaskStatus.SUCCESS } else { description = context.getString(R.string.settings_troubleshoot_test_account_settings_failed) @@ -45,10 +45,10 @@ class NotificationAccountSettingsTest @Inject constructor(@ApplicationContext pr } } } - status = NotificationTestStatus.SUCCESS + status = TaskStatus.SUCCESS } } else { - status = NotificationTestStatus.FAILED + status = TaskStatus.FAILED } } } diff --git a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationAvailableUnifiedDistributorsTest.kt b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationAvailableUnifiedDistributorsTest.kt index fcfb261c8292cd74f043d63c68a4861ba495d84c..955cc894b6c8250d4174788b72570bfcc24b0d4e 100644 --- a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationAvailableUnifiedDistributorsTest.kt +++ b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationAvailableUnifiedDistributorsTest.kt @@ -3,9 +3,9 @@ package org.futo.circles.feature.notifications.test.task import android.content.Context import dagger.hilt.android.qualifiers.ApplicationContext import org.futo.circles.R +import org.futo.circles.core.model.TaskStatus import org.futo.circles.feature.notifications.FcmHelper import org.futo.circles.feature.notifications.PushersManager -import org.futo.circles.model.NotificationTestStatus import javax.inject.Inject @@ -33,6 +33,6 @@ class NotificationAvailableUnifiedDistributorsTest @Inject constructor( quantity ) } - status = NotificationTestStatus.SUCCESS + status = TaskStatus.SUCCESS } } \ No newline at end of file diff --git a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationCurrentPushDistributorTest.kt b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationCurrentPushDistributorTest.kt index 38c63b6548070fcf4f6a8fc044478db9e38a048b..72a2a04a8afed71055d1fecb0aa22e298631140d 100644 --- a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationCurrentPushDistributorTest.kt +++ b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationCurrentPushDistributorTest.kt @@ -3,8 +3,8 @@ package org.futo.circles.feature.notifications.test.task import android.content.Context import dagger.hilt.android.qualifiers.ApplicationContext import org.futo.circles.R +import org.futo.circles.core.model.TaskStatus import org.futo.circles.feature.notifications.PushersManager -import org.futo.circles.model.NotificationTestStatus import javax.inject.Inject @@ -18,7 +18,7 @@ class NotificationCurrentPushDistributorTest @Inject constructor( R.string.settings_troubleshoot_test_current_distributor, pushersManager.getCurrentDistributorName() ) - status = NotificationTestStatus.SUCCESS + status = TaskStatus.SUCCESS } } \ No newline at end of file diff --git a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationFromPushGatewayTest.kt b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationFromPushGatewayTest.kt index c10de78d1a24de2f322f1c3b53ba504450b5b555..3a8dfc86544aeb4920c386cea334713495ec91df 100644 --- a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationFromPushGatewayTest.kt +++ b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationFromPushGatewayTest.kt @@ -9,8 +9,8 @@ import org.futo.circles.R import org.futo.circles.core.ErrorParser import org.futo.circles.core.provider.MatrixSessionProvider import org.futo.circles.core.extensions.coroutineScope +import org.futo.circles.core.model.TaskStatus import org.futo.circles.feature.notifications.PushersManager -import org.futo.circles.model.NotificationTestStatus import javax.inject.Inject class NotificationFromPushGatewayTest @Inject constructor( @@ -32,17 +32,17 @@ class NotificationFromPushGatewayTest @Inject constructor( if (pushReceived) { description = context.getString(R.string.settings_troubleshoot_test_push_loop_success) - status = NotificationTestStatus.SUCCESS + status = TaskStatus.SUCCESS } else { description = context.getString(R.string.settings_troubleshoot_test_push_loop_waiting_for_push) - status = NotificationTestStatus.RUNNING + status = TaskStatus.RUNNING } updateTestInfo() }, { description = ErrorParser.getErrorMessage(it) - status = NotificationTestStatus.FAILED + status = TaskStatus.FAILED updateTestInfo() } ) @@ -54,7 +54,7 @@ class NotificationFromPushGatewayTest @Inject constructor( pushReceived = true description = context.getString(R.string.settings_troubleshoot_test_push_loop_success) - status = NotificationTestStatus.SUCCESS + status = TaskStatus.SUCCESS updateTestInfo() } } diff --git a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationPushRulesSettingsTest.kt b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationPushRulesSettingsTest.kt index 5fbf45468e9d95c0da557be743ff321877d9e4fd..64a97f2daa2b0ab66993defbb50c87057acb657c 100644 --- a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationPushRulesSettingsTest.kt +++ b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationPushRulesSettingsTest.kt @@ -3,8 +3,8 @@ package org.futo.circles.feature.notifications.test.task import android.content.Context import dagger.hilt.android.qualifiers.ApplicationContext import org.futo.circles.R +import org.futo.circles.core.model.TaskStatus import org.futo.circles.core.provider.MatrixSessionProvider -import org.futo.circles.model.NotificationTestStatus import org.futo.circles.model.toNotificationAction import org.matrix.android.sdk.api.session.pushrules.RuleIds import org.matrix.android.sdk.api.session.pushrules.getActions @@ -43,12 +43,12 @@ class NotificationPushRulesSettingsTest @Inject constructor( if (oneOrMoreRuleIsOff) { description = context.getString(R.string.settings_troubleshoot_test_bing_settings_failed) - status = NotificationTestStatus.FAILED + status = TaskStatus.FAILED } else { description = if (oneOrMoreRuleAreSilent) { context.getString(R.string.settings_troubleshoot_test_bing_settings_success_with_warn) } else "" - status = NotificationTestStatus.SUCCESS + status = TaskStatus.SUCCESS } } } diff --git a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationSystemSettingsTest.kt b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationSystemSettingsTest.kt index 7bc36c365b5f53c0b04b27187840e65bdbfb0e34..c5792bdaa345ecf58029b6b21c60ef344679a141 100644 --- a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationSystemSettingsTest.kt +++ b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationSystemSettingsTest.kt @@ -9,7 +9,7 @@ import androidx.core.app.NotificationManagerCompat import androidx.core.content.ContextCompat import dagger.hilt.android.qualifiers.ApplicationContext import org.futo.circles.R -import org.futo.circles.model.NotificationTestStatus +import org.futo.circles.core.model.TaskStatus import javax.inject.Inject class NotificationSystemSettingsTest @Inject constructor( @@ -21,7 +21,7 @@ class NotificationSystemSettingsTest @Inject constructor( description = context.getString(R.string.settings_troubleshoot_test_system_settings_success) quickFix = null - status = NotificationTestStatus.SUCCESS + status = TaskStatus.SUCCESS } else { description = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && isNotificationsPermissionGranted( @@ -32,7 +32,7 @@ class NotificationSystemSettingsTest @Inject constructor( } else { context.getString(R.string.settings_troubleshoot_test_system_settings_failed) } - status = NotificationTestStatus.FAILED + status = TaskStatus.FAILED } } diff --git a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationTestSend.kt b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationTestSend.kt index 782ae8bc11cf2acd1bdd03bfe6de398f40cf8124..44dc73bfd1225076039fee6e4c65b951c08d7b6f 100644 --- a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationTestSend.kt +++ b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationTestSend.kt @@ -3,8 +3,8 @@ package org.futo.circles.feature.notifications.test.task import android.content.Context import dagger.hilt.android.qualifiers.ApplicationContext import org.futo.circles.R +import org.futo.circles.core.model.TaskStatus import org.futo.circles.feature.notifications.NotificationUtils -import org.futo.circles.model.NotificationTestStatus import javax.inject.Inject @@ -17,14 +17,14 @@ class NotificationTestSend @Inject constructor( notificationUtils.displayDiagnosticNotification() description = context.getString(R.string.settings_troubleshoot_test_notification_notice) - status = NotificationTestStatus.IDLE + status = TaskStatus.IDLE } override fun onTestPushClicked() { description = context.getString(R.string.settings_troubleshoot_test_notification_notification_clicked) quickFix = null - status = NotificationTestStatus.SUCCESS + status = TaskStatus.SUCCESS updateTestInfo() } } \ No newline at end of file diff --git a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationsEndpointAsTokenRegistrationTest.kt b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationsEndpointAsTokenRegistrationTest.kt index 98cb85bdbf2d298ab1229b69beb558931931e617..2ab66041e94a591e48a558fed525a2fec7104d5e 100644 --- a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationsEndpointAsTokenRegistrationTest.kt +++ b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationsEndpointAsTokenRegistrationTest.kt @@ -3,9 +3,9 @@ package org.futo.circles.feature.notifications.test.task import android.content.Context import dagger.hilt.android.qualifiers.ApplicationContext import org.futo.circles.R +import org.futo.circles.core.model.TaskStatus import org.futo.circles.core.provider.MatrixSessionProvider import org.futo.circles.feature.notifications.PushersManager -import org.futo.circles.model.NotificationTestStatus import org.matrix.android.sdk.api.session.pushers.PusherState import javax.inject.Inject @@ -16,11 +16,11 @@ class NotificationsEndpointAsTokenRegistrationTest @Inject constructor( override fun perform() { val endpoint = pushersManager.getEndpointOrToken() ?: run { - status = NotificationTestStatus.FAILED + status = TaskStatus.FAILED return } val session = MatrixSessionProvider.currentSession ?: run { - status = NotificationTestStatus.FAILED + status = TaskStatus.FAILED return } val pushers = session.pushersService().getPushers().filter { @@ -31,11 +31,11 @@ class NotificationsEndpointAsTokenRegistrationTest @Inject constructor( R.string.settings_troubleshoot_test_endpoint_registration_failed, context.getString(R.string.unexpected_error) ) - status = NotificationTestStatus.FAILED + status = TaskStatus.FAILED } else { description = context.getString(R.string.settings_troubleshoot_test_endpoint_registration_success) - status = NotificationTestStatus.SUCCESS + status = TaskStatus.SUCCESS } } } diff --git a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationsUnifiedPushEndpointTest.kt b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationsUnifiedPushEndpointTest.kt index 5e039839e47a9a26daea1af57c8470585dabeb4d..fa853dc7a26327b7fcd50eb262e7e0c4a2cb01ff 100644 --- a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationsUnifiedPushEndpointTest.kt +++ b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationsUnifiedPushEndpointTest.kt @@ -3,8 +3,8 @@ package org.futo.circles.feature.notifications.test.task import android.content.Context import dagger.hilt.android.qualifiers.ApplicationContext import org.futo.circles.R +import org.futo.circles.core.model.TaskStatus import org.futo.circles.feature.notifications.PushersManager -import org.futo.circles.model.NotificationTestStatus import javax.inject.Inject class NotificationsUnifiedPushEndpointTest @Inject constructor( @@ -19,11 +19,11 @@ class NotificationsUnifiedPushEndpointTest @Inject constructor( R.string.settings_troubleshoot_test_current_endpoint_success, endpoint ) - status = NotificationTestStatus.SUCCESS + status = TaskStatus.SUCCESS } else { description = context.getString(R.string.settings_troubleshoot_test_current_endpoint_failed) - status = NotificationTestStatus.FAILED + status = TaskStatus.FAILED } } } diff --git a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationsUnifiedPushGatewayTest.kt b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationsUnifiedPushGatewayTest.kt index 59175abfd29737c51aab2d099e811b5105ceab16..7453c1db2132031aafc29220d3287bcde88a192d 100644 --- a/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationsUnifiedPushGatewayTest.kt +++ b/app/src/main/java/org/futo/circles/feature/notifications/test/task/NotificationsUnifiedPushGatewayTest.kt @@ -3,8 +3,8 @@ package org.futo.circles.feature.notifications.test.task import android.content.Context import dagger.hilt.android.qualifiers.ApplicationContext import org.futo.circles.R +import org.futo.circles.core.model.TaskStatus import org.futo.circles.feature.notifications.PushersManager -import org.futo.circles.model.NotificationTestStatus import javax.inject.Inject class NotificationsUnifiedPushGatewayTest @Inject constructor( @@ -17,6 +17,6 @@ class NotificationsUnifiedPushGatewayTest @Inject constructor( R.string.settings_troubleshoot_test_current_gateway, pushersManager.getPushGateway() ) - status = NotificationTestStatus.SUCCESS + status = TaskStatus.SUCCESS } } \ No newline at end of file diff --git a/app/src/main/java/org/futo/circles/feature/people/PeopleDataSource.kt b/app/src/main/java/org/futo/circles/feature/people/PeopleDataSource.kt index d4cc88f3fcb85afc64e7c770d36423d1987f2ac8..b93d28a58addba8b84b8d48bef597d842b75f462 100644 --- a/app/src/main/java/org/futo/circles/feature/people/PeopleDataSource.kt +++ b/app/src/main/java/org/futo/circles/feature/people/PeopleDataSource.kt @@ -11,8 +11,7 @@ import kotlinx.coroutines.withContext import org.futo.circles.core.extensions.createResult import org.futo.circles.core.provider.MatrixSessionProvider import org.futo.circles.core.select_users.SearchUserDataSource -import org.futo.circles.core.utils.getSharedCircleFor -import org.futo.circles.core.utils.getSharedCirclesSpaceId +import org.futo.circles.core.workspace.SharedCircleDataSource import org.futo.circles.mapping.toPeopleUserListItem import org.futo.circles.model.PeopleHeaderItem import org.futo.circles.model.PeopleItemType @@ -24,11 +23,12 @@ import org.matrix.android.sdk.api.session.user.model.User import javax.inject.Inject class PeopleDataSource @Inject constructor( - private val searchUserDataSource: SearchUserDataSource + private val searchUserDataSource: SearchUserDataSource, + private val sharedCircleDataSource: SharedCircleDataSource ) { private val session = MatrixSessionProvider.currentSession - private val profileRoomId = getSharedCirclesSpaceId() ?: "" + private val profileRoomId = sharedCircleDataSource.getSharedCirclesSpaceId() ?: "" suspend fun acceptFollowRequest(userId: String) = createResult { session?.roomService()?.getRoom(profileRoomId)?.membershipService()?.invite(userId) @@ -127,12 +127,12 @@ class PeopleDataSource @Inject constructor( } private fun isMyFollower(userId: String): Boolean { - val mySharedCircleMembers = getSharedCirclesSpaceId()?.let { - session?.getRoom(it)?.roomSummary()?.otherMemberIds - } ?: emptyList() + val mySharedCircleMembers = + session?.getRoom(profileRoomId)?.roomSummary()?.otherMemberIds ?: emptyList() return mySharedCircleMembers.contains(userId) } - private fun amIFollowing(userId: String) = getSharedCircleFor(userId) != null + private fun amIFollowing(userId: String) = + sharedCircleDataSource.getSharedCircleFor(userId) != null } \ No newline at end of file diff --git a/app/src/main/java/org/futo/circles/feature/people/UserOptionsDataSource.kt b/app/src/main/java/org/futo/circles/feature/people/UserOptionsDataSource.kt index 716e420f1cc7232fef8923c9b6590ede3c85fe54..4a234e39a5263b69f0e4ca52a5757633a228820f 100644 --- a/app/src/main/java/org/futo/circles/feature/people/UserOptionsDataSource.kt +++ b/app/src/main/java/org/futo/circles/feature/people/UserOptionsDataSource.kt @@ -3,10 +3,12 @@ package org.futo.circles.feature.people import org.futo.circles.core.extensions.Response import org.futo.circles.core.extensions.createResult import org.futo.circles.core.provider.MatrixSessionProvider -import org.futo.circles.core.utils.getSharedCircleFor +import org.futo.circles.core.workspace.SharedCircleDataSource import javax.inject.Inject -class UserOptionsDataSource @Inject constructor() { +class UserOptionsDataSource @Inject constructor( + private val sharedCircleDataSource: SharedCircleDataSource +) { val ignoredUsersLiveData = MatrixSessionProvider.currentSession?.userService()?.getIgnoredUsersLive() @@ -19,10 +21,11 @@ class UserOptionsDataSource @Inject constructor() { MatrixSessionProvider.currentSession?.userService()?.unIgnoreUserIds(listOf(userId)) } - fun amIFollowingUser(userId: String): Boolean = getSharedCircleFor(userId) != null + fun amIFollowingUser(userId: String): Boolean = + sharedCircleDataSource.getSharedCircleFor(userId) != null suspend fun unFollowUser(userId: String): Response<Unit?> = createResult { MatrixSessionProvider.currentSession?.roomService() - ?.leaveRoom(getSharedCircleFor(userId)?.roomId ?: "") + ?.leaveRoom(sharedCircleDataSource.getSharedCircleFor(userId)?.roomId ?: "") } } \ No newline at end of file diff --git a/app/src/main/java/org/futo/circles/feature/people/user/UserDataSource.kt b/app/src/main/java/org/futo/circles/feature/people/user/UserDataSource.kt index 1d8234ae48d918dc1daa4e309d2cbd362e88a645..677e3c57faa025c123f9ce3ba9e86614805e90f1 100644 --- a/app/src/main/java/org/futo/circles/feature/people/user/UserDataSource.kt +++ b/app/src/main/java/org/futo/circles/feature/people/user/UserDataSource.kt @@ -13,7 +13,7 @@ import org.futo.circles.core.extensions.getOrThrow import org.futo.circles.core.extensions.getRoomOwners import org.futo.circles.core.model.TIMELINE_TYPE import org.futo.circles.core.provider.MatrixSessionProvider -import org.futo.circles.core.utils.getSharedCircleFor +import org.futo.circles.core.workspace.SharedCircleDataSource import org.futo.circles.mapping.toTimelineRoomListItem import org.futo.circles.model.TimelineHeaderItem import org.futo.circles.model.TimelineListItem @@ -26,7 +26,8 @@ import javax.inject.Inject @ViewModelScoped class UserDataSource @Inject constructor( - savedStateHandle: SavedStateHandle + savedStateHandle: SavedStateHandle, + private val sharedCircleDataSource: SharedCircleDataSource ) { private val userId: String = savedStateHandle.getOrThrow("userId") @@ -70,7 +71,7 @@ class UserDataSource @Inject constructor( .map { list -> filterUsersTimelines(list) }.asFlow() private suspend fun getAllSharedTimelinesFlow() = session.roomService().getRoomSummaryLive( - getSharedCircleFor(userId)?.roomId ?: "" + sharedCircleDataSource.getSharedCircleFor(userId)?.roomId ?: "" ).asFlow().map { sharedSummary -> sharedSummary.getOrNull()?.let { mapSharedTimelines(it) } ?: emptyList() } diff --git a/app/src/main/java/org/futo/circles/feature/room/select/SelectRoomsDataSource.kt b/app/src/main/java/org/futo/circles/feature/room/select/SelectRoomsDataSource.kt index 2e8ff781d7df991a2d7e23cdc628d54f1599f985..8b625ae69546a8056bef67f5e56cf241814c892b 100644 --- a/app/src/main/java/org/futo/circles/feature/room/select/SelectRoomsDataSource.kt +++ b/app/src/main/java/org/futo/circles/feature/room/select/SelectRoomsDataSource.kt @@ -13,12 +13,13 @@ import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.flowOn import org.futo.circles.core.extensions.getOrThrow import org.futo.circles.core.mapping.toSelectableRoomListItem -import org.futo.circles.core.model.CIRCLE_TAG import org.futo.circles.core.model.CircleRoomTypeArg import org.futo.circles.core.model.GALLERY_TYPE import org.futo.circles.core.model.GROUP_TYPE import org.futo.circles.core.model.SelectableRoomListItem import org.futo.circles.core.provider.MatrixSessionProvider +import org.futo.circles.core.workspace.SharedCircleDataSource +import org.futo.circles.feature.circles.CirclesDataSource import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.RoomSummary import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams @@ -26,7 +27,8 @@ import javax.inject.Inject @ViewModelScoped class SelectRoomsDataSource @Inject constructor( - savedStateHandle: SavedStateHandle + savedStateHandle: SavedStateHandle, + private val circleDataSource: CirclesDataSource ) { val ordinal = savedStateHandle.getOrThrow<Int>(SelectRoomsFragment.TYPE_ORDINAL) @@ -45,7 +47,7 @@ class SelectRoomsDataSource @Inject constructor( }.flowOn(Dispatchers.IO).distinctUntilChanged() private fun getRoomsFlowWithType(): Flow<List<RoomSummary>> = when (roomType) { - CircleRoomTypeArg.Circle -> getFilteredRoomsFlow { it.hasTag(CIRCLE_TAG) && it.membership == Membership.JOIN } + CircleRoomTypeArg.Circle -> getFilteredRoomsFlow { circleDataSource.isJoinedCircle(it) } CircleRoomTypeArg.Group -> getFilteredRoomsFlow { (it.roomType == GROUP_TYPE && it.membership == Membership.JOIN) } CircleRoomTypeArg.Photo -> getFilteredRoomsFlow { (it.roomType == GALLERY_TYPE && it.membership == Membership.JOIN) } } diff --git a/app/src/main/java/org/futo/circles/feature/settings/SettingsFragment.kt b/app/src/main/java/org/futo/circles/feature/settings/SettingsFragment.kt index 6b0de4a53231070786e0b9b59a42d3385135a0a3..e8a3f3d145de0f1bd25965c8df153d710e9875ae 100644 --- a/app/src/main/java/org/futo/circles/feature/settings/SettingsFragment.kt +++ b/app/src/main/java/org/futo/circles/feature/settings/SettingsFragment.kt @@ -22,7 +22,6 @@ import org.futo.circles.core.extensions.showSuccess import org.futo.circles.core.extensions.withConfirmation import org.futo.circles.core.model.DeactivateAccount import org.futo.circles.core.model.LoadingData -import org.futo.circles.core.notices.SystemNoticesCountSharedViewModel import org.futo.circles.core.provider.PreferencesProvider import org.futo.circles.core.view.LoadingDialog import org.futo.circles.databinding.FragmentSettingsBinding @@ -33,7 +32,6 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) { private val binding by viewBinding(FragmentSettingsBinding::bind) private val viewModel by viewModels<SettingsViewModel>() - private val systemNoticesCountViewModel by activityViewModels<SystemNoticesCountSharedViewModel>() private val loadingDialog by lazy { LoadingDialog(requireContext()) } private val preferencesProvider by lazy { PreferencesProvider(requireContext()) } private val navigator by lazy { SettingsNavigator(this) } @@ -46,44 +44,43 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) { private fun setupViews() { with(binding) { - tvLogout.setOnClickListener { withConfirmation(LogOut()) { viewModel.logOut() } } + tvLogout.setOnClickListener { + withConfirmation(LogOut()) { + loadingDialog.handleLoading(LoadingData(R.string.log_out)) + viewModel.logOut() + } + } tvSwitchUser.setOnClickListener { withConfirmation(SwitchUser()) { (activity as? MainActivity)?.stopSyncAndRestart() } } ivProfile.setOnClickListener { navigator.navigateToProfile() } tvChangePassword.setOnClickListener { viewModel.handleChangePasswordFlow() } tvDeactivate.setOnClickListener { withConfirmation(DeactivateAccount()) { - loadingDialog.handleLoading(LoadingData(total = 0)) + loadingDialog.handleLoading(LoadingData()) viewModel.deactivateAccount() } } tvLoginSessions.setOnClickListener { navigator.navigateToActiveSessions() } - lSystemNotices.setOnClickListener { navigator.navigateToSystemNotices() } tvClearCache.setOnClickListener { viewModel.clearCash(requireContext()) } tvVersion.setOnLongClickListener { toggleDeveloperMode(); true } tvPushNotifications.setOnClickListener { navigator.navigateToPushSettings() } - ivShareProfile.setOnClickListener { navigator.navigateToShareProfile() } + ivShareProfile.setOnClickListener { navigator.navigateToShareProfile(viewModel.getSharedCircleSpaceId()) } } setVersion() } private fun setupObservers() { viewModel.logOutLiveData.observeResponse(this, - success = { clearSessionAndRestart() } + success = { clearSessionAndRestart() }, + onRequestInvoked = { loadingDialog.dismiss() } ) viewModel.profileLiveData.observeData(this) { it.getOrNull()?.let { bindProfile(it) } } - viewModel.loadingLiveData.observeData(this) { - loadingDialog.handleLoading(it) - } viewModel.deactivateLiveData.observeResponse(this, success = { clearSessionAndRestart() }, error = { showError(getString(org.futo.circles.auth.R.string.invalid_auth)) }, onRequestInvoked = { loadingDialog.dismiss() } ) - systemNoticesCountViewModel.systemNoticesCountLiveData?.observeData(this) { - binding.ivNoticesCount.setCount(it ?: 0) - } viewModel.startReAuthEventLiveData.observeData(this) { navigator.navigateToReAuthStages() } diff --git a/app/src/main/java/org/futo/circles/feature/settings/SettingsNavigator.kt b/app/src/main/java/org/futo/circles/feature/settings/SettingsNavigator.kt index ae245082367ec9aa4ef3a1c2189d26edaba9b632..1e095afa621d733b329e2fdcd63a11c4c3551f79 100644 --- a/app/src/main/java/org/futo/circles/feature/settings/SettingsNavigator.kt +++ b/app/src/main/java/org/futo/circles/feature/settings/SettingsNavigator.kt @@ -4,8 +4,6 @@ import androidx.navigation.fragment.findNavController import org.futo.circles.R import org.futo.circles.core.extensions.navigateSafe import org.futo.circles.core.extensions.showError -import org.futo.circles.core.utils.getSharedCirclesSpaceId -import org.futo.circles.core.utils.getSystemNoticesRoomId class SettingsNavigator(private val fragment: SettingsFragment) { @@ -19,16 +17,6 @@ class SettingsNavigator(private val fragment: SettingsFragment) { .navigateSafe(SettingsFragmentDirections.toActiveSessionsDialogFragment()) } - fun navigateToSystemNotices() { - val systemNoticesRoomId = getSystemNoticesRoomId() ?: run { - fragment.showError(fragment.getString(org.futo.circles.core.R.string.system_notices_room_not_found)) - return - } - fragment.findNavController().navigateSafe( - SettingsFragmentDirections.toSystemNoticesDialogFragment(systemNoticesRoomId) - ) - } - fun navigateToMatrixChangePassword() { fragment.findNavController() .navigateSafe(SettingsFragmentDirections.toChangePasswordDialogFragment()) @@ -44,8 +32,8 @@ class SettingsNavigator(private val fragment: SettingsFragment) { .navigateSafe(SettingsFragmentDirections.toReAuthStagesDialogFragment()) } - fun navigateToShareProfile() { - val sharedSpaceId = getSharedCirclesSpaceId() ?: kotlin.run { + fun navigateToShareProfile(sharedSpaceId: String?) { + sharedSpaceId ?: kotlin.run { fragment.showError( fragment.requireContext().getString(R.string.shared_circles_space_not_found) ) diff --git a/app/src/main/java/org/futo/circles/feature/settings/SettingsViewModel.kt b/app/src/main/java/org/futo/circles/feature/settings/SettingsViewModel.kt index deac30615ed3162f400e29716c339a330026efb5..38a26546737f4241dd648e71a3d26c77bef98e27 100644 --- a/app/src/main/java/org/futo/circles/feature/settings/SettingsViewModel.kt +++ b/app/src/main/java/org/futo/circles/feature/settings/SettingsViewModel.kt @@ -8,16 +8,17 @@ import org.futo.circles.core.SingleEventLiveData import org.futo.circles.core.extensions.Response import org.futo.circles.core.extensions.launchBg import org.futo.circles.core.utils.LauncherActivityUtils +import org.futo.circles.core.workspace.SharedCircleDataSource import javax.inject.Inject @HiltViewModel class SettingsViewModel @Inject constructor( private val settingsDataSource: SettingsDataSource, - private val logoutDataSource: LogoutDataSource + private val logoutDataSource: LogoutDataSource, + private val sharedCircleDataSource: SharedCircleDataSource ) : ViewModel() { val profileLiveData = settingsDataSource.profileLiveData - val loadingLiveData = logoutDataSource.loadingLiveData val passPhraseLoadingLiveData = settingsDataSource.passPhraseLoadingLiveData val startReAuthEventLiveData = settingsDataSource.startReAuthEventLiveData val logOutLiveData = SingleEventLiveData<Response<Unit?>>() @@ -58,4 +59,6 @@ class SettingsViewModel @Inject constructor( launchBg { LauncherActivityUtils.clearCache(context) } clearCacheLiveData.postValue(Unit) } + + fun getSharedCircleSpaceId(): String? = sharedCircleDataSource.getSharedCirclesSpaceId() } \ No newline at end of file diff --git a/app/src/main/java/org/futo/circles/feature/timeline/list/UploadMediaProgressHelper.kt b/app/src/main/java/org/futo/circles/feature/timeline/list/UploadMediaProgressHelper.kt index 162c2c9298d64c91f5c7e4e1a90ca19119846cdf..880d34cbce39c0e7db5bbf9e9eb6be48dffc055f 100644 --- a/app/src/main/java/org/futo/circles/feature/timeline/list/UploadMediaProgressHelper.kt +++ b/app/src/main/java/org/futo/circles/feature/timeline/list/UploadMediaProgressHelper.kt @@ -15,7 +15,7 @@ object UploadMediaProgressHelper { when (state) { ContentUploadStateTracker.State.CompressingImage -> { loadingView.visible() - loadingView.setMessage(R.string.compressing) + loadingView.setProgress(LoadingData(R.string.compressing)) } is ContentUploadStateTracker.State.CompressingVideo -> { diff --git a/app/src/main/java/org/futo/circles/model/NotificationTestListItem.kt b/app/src/main/java/org/futo/circles/model/NotificationTestListItem.kt index dd6e844ccf44ed3c6b27f1d1a4823f5c78d034cc..82aa257167aaee2a05f353045791558dad928ff8 100644 --- a/app/src/main/java/org/futo/circles/model/NotificationTestListItem.kt +++ b/app/src/main/java/org/futo/circles/model/NotificationTestListItem.kt @@ -1,11 +1,12 @@ package org.futo.circles.model import org.futo.circles.core.list.IdEntity +import org.futo.circles.core.model.TaskStatus data class NotificationTestListItem( val titleId: Int, val message: String, - val status: NotificationTestStatus, + val status: TaskStatus, val hasFix: Boolean ) : IdEntity<Int> { override val id: Int = titleId diff --git a/app/src/main/java/org/futo/circles/model/NotificationTestStatus.kt b/app/src/main/java/org/futo/circles/model/NotificationTestStatus.kt deleted file mode 100644 index 56abc6886353a041c5f41630e83dbfb98c494c21..0000000000000000000000000000000000000000 --- a/app/src/main/java/org/futo/circles/model/NotificationTestStatus.kt +++ /dev/null @@ -1,8 +0,0 @@ -package org.futo.circles.model - -enum class NotificationTestStatus { - IDLE, - RUNNING, - SUCCESS, - FAILED -} \ No newline at end of file diff --git a/app/src/main/java/org/futo/circles/model/PeopleListItem.kt b/app/src/main/java/org/futo/circles/model/PeopleListItem.kt index ca5d9b2d2f904ec2f8b292107e4d0c0412ed5f1d..4247cdaf0ac49d0d697f8b81827dca3a432c148b 100644 --- a/app/src/main/java/org/futo/circles/model/PeopleListItem.kt +++ b/app/src/main/java/org/futo/circles/model/PeopleListItem.kt @@ -15,7 +15,7 @@ data class PeopleHeaderItem( override val id: String = titleRes.toString() companion object { - val friends = PeopleHeaderItem(R.string.friends) + val friends = PeopleHeaderItem(org.futo.circles.auth.R.string.friends) val followersUsersHeader = PeopleHeaderItem(R.string.followers) val followingUsersHeader = PeopleHeaderItem(R.string.following) val knownUsersHeader = PeopleHeaderItem(R.string.known_users) diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml index 519dc47064000f3e5c29d920c15086e02632a615..f36e2bf229a3e2dc93f76dac7b77c58df8f7c24c 100644 --- a/app/src/main/res/layout/fragment_settings.xml +++ b/app/src/main/res/layout/fragment_settings.xml @@ -121,79 +121,48 @@ android:layout_height="wrap_content" android:text="@string/notifications" /> - <org.futo.circles.core.view.SettingsMenuItemView + <TextView android:id="@+id/tvPushNotifications" + style="@style/settingMenuItem" android:layout_width="match_parent" android:layout_height="wrap_content" - app:optionIcon="@drawable/ic_notifications" - app:optionName="@string/push_notifications" /> - - - <androidx.constraintlayout.widget.ConstraintLayout - android:id="@+id/lSystemNotices" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:background="?selectableItemBackground" - android:clickable="true" - android:focusable="true"> - - <TextView - android:id="@+id/tvSystemNotices" - style="@style/settingMenuItem" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:background="@null" - android:clickable="false" - android:paddingEnd="8dp" - android:text="@string/system_notices" - app:drawableStartCompat="@drawable/ic_error" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" - tools:ignore="RtlSymmetry" /> - - <org.futo.circles.core.view.NotificationCounterView - android:id="@+id/ivNoticesCount" - android:layout_width="18dp" - android:layout_height="0dp" - android:layout_marginTop="2dp" - android:background="@android:color/holo_red_dark" - android:visibility="gone" - app:layout_constraintStart_toEndOf="@id/tvSystemNotices" - app:layout_constraintTop_toTopOf="parent" - tools:visibility="visible" /> - - - </androidx.constraintlayout.widget.ConstraintLayout> + android:text="@string/push_notifications" + app:drawableStartCompat="@drawable/ic_notifications" /> <TextView style="@style/settingMenuHeader" android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="@string/account" /> + android:text="@string/session" /> <org.futo.circles.core.view.SettingsMenuItemView - android:id="@+id/tvChangePassword" + android:id="@+id/tvLoginSessions" android:layout_width="match_parent" android:layout_height="wrap_content" - app:optionIcon="@drawable/ic_lock" - app:optionName="@string/change_password" /> + app:optionIcon="@drawable/ic_phone" + app:optionName="@string/login_sessions" /> - <org.futo.circles.core.view.SettingsMenuItemView - android:id="@+id/tvLoginSessions" + <TextView + android:id="@+id/tvClearCache" + style="@style/settingMenuItem" android:layout_width="match_parent" android:layout_height="wrap_content" - app:optionIcon="@drawable/ic_phone" - app:optionName="@string/login_sessions" /> + android:text="@string/clear_cache_and_reload" + app:drawableStartCompat="@drawable/ic_reload" /> + <TextView + style="@style/settingMenuHeader" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/account" /> <org.futo.circles.core.view.SettingsMenuItemView - android:id="@+id/tvClearCache" + android:id="@+id/tvChangePassword" android:layout_width="match_parent" android:layout_height="wrap_content" - app:optionIcon="@drawable/ic_reload" - app:optionName="@string/clear_cache_and_reload" /> + app:optionIcon="@drawable/ic_lock" + app:optionName="@string/change_password" /> <org.futo.circles.core.view.SettingsMenuItemView diff --git a/app/src/main/res/layout/fragment_setup_circles.xml b/app/src/main/res/layout/fragment_setup_circles.xml deleted file mode 100644 index 9e3a40256a8609d71d3795b9df73bdbb9233bcc5..0000000000000000000000000000000000000000 --- a/app/src/main/res/layout/fragment_setup_circles.xml +++ /dev/null @@ -1,88 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" - android:layout_width="match_parent" - android:layout_height="match_parent"> - - - <com.google.android.material.appbar.MaterialToolbar - android:id="@+id/toolbar" - android:layout_width="0dp" - android:layout_height="?attr/actionBarSize" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" - app:title="@string/setup_circles" - app:titleCentered="true" /> - - <View - android:id="@+id/toolbarDivider" - android:layout_width="0dp" - android:layout_height="@dimen/divider_height" - android:background="@color/divider_color" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/toolbar" /> - - <androidx.constraintlayout.widget.Guideline - android:id="@+id/guidelineStart" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:orientation="vertical" - app:layout_constraintGuide_begin="36dp" /> - - <androidx.constraintlayout.widget.Guideline - android:id="@+id/guidelineEnd" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:orientation="vertical" - app:layout_constraintGuide_end="36dp" /> - - <androidx.recyclerview.widget.RecyclerView - android:id="@+id/rvSetupCircles" - android:layout_width="0dp" - android:layout_height="0dp" - app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" - app:layout_constraintBottom_toTopOf="@id/tvEncryptionWarning" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/toolbarDivider" /> - - <TextView - android:id="@+id/tvEncryptionWarning" - style="@style/footNote" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_marginBottom="16dp" - android:drawablePadding="8dp" - android:text="@string/circle_encryption_warning" - android:textColor="@color/yellow" - app:drawableStartCompat="@drawable/ic_info" - app:drawableTint="@color/yellow" - app:layout_constraintBottom_toTopOf="@id/btnSave" - app:layout_constraintEnd_toEndOf="@id/guidelineEnd" - app:layout_constraintStart_toStartOf="@id/guidelineStart" /> - - <org.futo.circles.core.view.LoadingButton - android:id="@+id/btnSave" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_marginStart="24dp" - android:layout_marginTop="16dp" - android:layout_marginBottom="24dp" - android:text="@string/save" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toEndOf="@id/guidelineEnd" - app:layout_constraintStart_toEndOf="@id/btnSkip" /> - - <com.google.android.material.button.MaterialButton - android:id="@+id/btnSkip" - style="@style/NegativeButtonStyle" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:text="@string/skip" - app:layout_constraintBottom_toBottomOf="@id/btnSave" - app:layout_constraintEnd_toStartOf="@id/btnSave" - app:layout_constraintStart_toStartOf="@id/guidelineStart" /> - -</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/list_item_setup_circle.xml b/app/src/main/res/layout/list_item_setup_circle.xml deleted file mode 100644 index 06ae73afb675c6ee4b13666cc4170688ebe354ab..0000000000000000000000000000000000000000 --- a/app/src/main/res/layout/list_item_setup_circle.xml +++ /dev/null @@ -1,54 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<androidx.constraintlayout.widget.ConstraintLayout 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="wrap_content" - android:background="?selectableItemBackground" - android:clickable="true" - android:focusable="true" - android:padding="4dp"> - - - <com.google.android.material.imageview.ShapeableImageView - android:id="@+id/ivCircleCover" - android:layout_width="@dimen/group_icon_size" - android:layout_height="@dimen/group_icon_size" - android:scaleType="centerCrop" - android:src="@drawable/add_image_placeholder" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" - app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.App.GroupIconRadius" /> - - <TextView - android:id="@+id/tvCircleName" - style="@style/title2" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:ellipsize="end" - android:gravity="center" - android:lines="1" - app:layout_constraintBottom_toTopOf="@id/tvUserName" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toEndOf="@id/ivCircleCover" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintVertical_chainStyle="packed" - tools:text="texsdt" /> - - <TextView - android:id="@+id/tvUserName" - style="@style/subheadline" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_marginTop="4dp" - android:ellipsize="end" - android:gravity="center" - android:lines="1" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="@id/tvCircleName" - app:layout_constraintTop_toBottomOf="@id/tvCircleName" - tools:text="texsdt" /> - -</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/app/src/main/res/navigation/nav_graph_start_host.xml b/app/src/main/res/navigation/nav_graph_start_host.xml index 2786cacc4ed47989321accf1d8441e449d03cfd6..419cdf7644f6508a507d49ed08438e90b173a10f 100644 --- a/app/src/main/res/navigation/nav_graph_start_host.xml +++ b/app/src/main/res/navigation/nav_graph_start_host.xml @@ -54,18 +54,6 @@ </action> </fragment> - <fragment - android:id="@+id/setupCirclesFragment" - android:name="org.futo.circles.feature.circles.setup.SetupCirclesFragment" - android:label="SetupCirclesFragment" - tools:layout="@layout/fragment_setup_circles"> - <action - android:id="@+id/to_homeFragment" - app:destination="@id/homeFragment" - app:popUpTo="@id/setupCirclesFragment" - app:popUpToInclusive="true" /> - </fragment> - <include app:graph="@navigation/nav_graph_auth" /> <dialog diff --git a/app/src/main/res/navigation/settings_nav_graph.xml b/app/src/main/res/navigation/settings_nav_graph.xml index 18e838fedbccb5547e14a613d2794c2f08395bf7..f4e9516a4a7bc25e34d310253aa49db3ca94e132 100644 --- a/app/src/main/res/navigation/settings_nav_graph.xml +++ b/app/src/main/res/navigation/settings_nav_graph.xml @@ -19,22 +19,6 @@ <action android:id="@+id/to_activeSessionsDialogFragment" app:destination="@id/log_in_sessions_nav_graph" /> - <action - android:id="@+id/to_systemNoticesDialogFragment" - app:destination="@id/systemNoticesDialogFragment"> - - <argument - android:name="roomId" - app:argType="string" - app:nullable="false" /> - - <argument - android:name="type" - android:defaultValue="Group" - app:argType="org.futo.circles.core.model.CircleRoomTypeArg" - app:nullable="false" /> - - </action> <action android:id="@+id/to_reAuthStagesDialogFragment" app:destination="@id/reAuthStagesDialogFragment" /> @@ -68,22 +52,6 @@ android:name="org.futo.circles.auth.feature.change_password.ChangePasswordDialogFragment" android:label="ChangePasswordDialogFragment" tools:layout="@layout/dialog_fragment_change_password" /> - <dialog - android:id="@+id/systemNoticesDialogFragment" - android:name="org.futo.circles.core.notices.SystemNoticesDialogFragment" - tools:layout="@layout/dialog_fragment_system_notices"> - - <argument - android:name="roomId" - app:argType="string" - app:nullable="false" /> - - <argument - android:name="type" - app:argType="org.futo.circles.core.model.CircleRoomTypeArg" - app:nullable="false" /> - - </dialog> <dialog android:id="@+id/shareRoomDialogFragment" diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 57661aa9dd34eb225ff47962361132abbd0c786f..8557874102522cc5ccc2c15d3a1b3d2b371551c8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -26,22 +26,12 @@ <string name="create_new_group">Create new group</string> <string name="create_new_circle">Create new circle</string> <string name="create">Create</string> - <string name="group_name">Group name</string> - <string name="circle_name">Circle name</string> - <string name="group_topic_optional">Group topic (optional)</string> - <string name="group_topic">Group topic</string> - <string name="setup_circles">Setup Circles</string> - <string name="circle_encryption_warning">NOTE: Circle name and cover image are not encrypted</string> - <string name="friends">Friends</string> - <string name="family">Family</string> - <string name="community">Community</string> <string name="circles_created">Circles created</string> <string name="private_circles">Private Circles</string> <string name="log_out">Log out</string> <string name="others">Others</string> <string name="following_format">Following %d</string> <string name="followed_by_format">Followed by %d</string> - <string name="group_encryption_warning">NOTE: Group name, topic and cover image are not encrypted</string> <string name="create_post">Create post</string> <string name="create_poll">Create poll</string> <string name="send">Send</string> @@ -81,8 +71,6 @@ <string name="hundred">100</string> <string name="severity_formatter">Severity: %d</string> <string name="add_reaction">Add reaction</string> - <string name="remove_from_this_circle_but_do_not_unfollow">Remove from this circle, but do not unfollow</string> - <string name="unfollow_completely_remove_from_all_circles">Unfollow completely (remove from all circles)</string> <string name="unfollow">Unfollow</string> <string name="requested_to_follow_format">%s requested to follow</string> <string name="requested_to_join">Requested to join</string> @@ -125,11 +113,6 @@ <string name="add_link">Add link</string> <string name="switch_user">Switch User</string> <string name="search_people">Search people</string> - <string name="circle_type">Circle type</string> - <string name="public_type">Public</string> - <string name="private_type">Private</string> - <string name="public_circle_explanation">Other users can ask to join</string> - <string name="private_circle_explanation">Accessible only by your invitation</string> <string name="request_sent">Request sent</string> <string name="wants_to_follow_you">wants to follow you</string> <string name="notification_unknown_room_name">Room</string> @@ -207,7 +190,6 @@ <string name="unifiedpush_distributors_dialog_title">Choose how to receive notifications</string> <string name="thread_format">%s (thread)</string> <string name="unexpected_error">Something went wrong</string> - <string name="configuring_workspace">Configuring workspace</string> <string name="shared_circles">Shared Circles</string> <string name="save">Save</string> <string name="joined_members_count">Joined members: %d</string> @@ -226,6 +208,8 @@ <string name="circles_empty_message">Create your first Circle</string> <string name="people_empty_message">Members of Circles and Groups you are joined will be shown here</string> <string name="creating_timeline">Creating timeline</string> + <string name="group_topic_optional">Group topic (optional)</string> + <string name="session">Session</string> <string-array name="report_categories"> <item>@string/crude_language</item> @@ -241,12 +225,6 @@ <item>@string/other_prohibited_content</item> </string-array> - <string-array name="setup_circles_list"> - <item>@string/friends</item> - <item>@string/family</item> - <item>@string/community</item> - </string-array> - <plurals name="notification_compat_summary_line_for_room"> <item quantity="one">%1$s: %2$d message</item> <item quantity="other">%1$s: %2$d messages</item> diff --git a/auth/src/main/java/org/futo/circles/auth/feature/log_in/log_out/LogoutDataSource.kt b/auth/src/main/java/org/futo/circles/auth/feature/log_in/log_out/LogoutDataSource.kt index 8bc23a8487f70b27db2c21618bcca8e59be9ffc3..95ce658c1636f8e22e635f765ca84d1b08645504 100644 --- a/auth/src/main/java/org/futo/circles/auth/feature/log_in/log_out/LogoutDataSource.kt +++ b/auth/src/main/java/org/futo/circles/auth/feature/log_in/log_out/LogoutDataSource.kt @@ -1,30 +1,13 @@ package org.futo.circles.auth.feature.log_in.log_out -import androidx.lifecycle.MutableLiveData -import org.futo.circles.auth.R import org.futo.circles.core.extensions.createResult -import org.futo.circles.core.model.LoadingData import org.futo.circles.core.provider.MatrixSessionProvider import javax.inject.Inject class LogoutDataSource @Inject constructor() { - private val session = MatrixSessionProvider.getSessionOrThrow() - - val loadingLiveData = MutableLiveData<LoadingData>() - private val loadingData = LoadingData(total = 0) - - suspend fun logOut() = createResult { - loadingLiveData.postValue( - loadingData.apply { - messageId = R.string.log_out - isLoading = true - } - ) - session.signOutService().signOut(true) - loadingLiveData.postValue(loadingData.apply { isLoading = false }) + MatrixSessionProvider.getSessionOrThrow().signOutService().signOut(true) } - } \ No newline at end of file diff --git a/auth/src/main/java/org/futo/circles/auth/feature/log_in/stages/LogInStagesFragment.kt b/auth/src/main/java/org/futo/circles/auth/feature/log_in/stages/LogInStagesFragment.kt index 7e940c2afe00975ec49068c1eb95a96e3391f814..4b0999d38f2aa46a7270270245ec1e08fdf97797 100644 --- a/auth/src/main/java/org/futo/circles/auth/feature/log_in/stages/LogInStagesFragment.kt +++ b/auth/src/main/java/org/futo/circles/auth/feature/log_in/stages/LogInStagesFragment.kt @@ -17,7 +17,6 @@ import org.futo.circles.auth.base.LoginStageNavigationEvent import org.futo.circles.auth.databinding.FragmentLoginStagesBinding import org.futo.circles.auth.feature.log_in.recovery.EnterPassPhraseDialog import org.futo.circles.auth.feature.log_in.recovery.EnterPassPhraseDialogListener -import org.futo.circles.core.CirclesAppConfig import org.futo.circles.core.extensions.navigateSafe import org.futo.circles.core.extensions.observeData import org.futo.circles.core.extensions.observeResponse @@ -79,15 +78,11 @@ class LogInStagesFragment : Fragment(R.layout.fragment_login_stages), viewModel.passPhraseLoadingLiveData.observeData(this) { loadingDialog.handleLoading(it) } - viewModel.spacesTreeLoadingLiveData.observeData(this) { - loadingDialog.handleLoading(it) - } viewModel.loginNavigationLiveData.observeData(this) { event -> when (event) { - LoginNavigationEvent.Main -> navigateToBottomMenuFragment() - LoginNavigationEvent.SetupCircles -> navigateToSetupCirclesOrHome() + LoginNavigationEvent.Main -> navigateToHome() LoginNavigationEvent.PassPhrase -> showPassPhraseDialog() - else -> navigateToBottomMenuFragment() + else -> navigateToHome() } } viewModel.messageEventLiveData.observeData(this) { messageId -> @@ -123,19 +118,10 @@ class LogInStagesFragment : Fragment(R.layout.fragment_login_stages), } } - private fun navigateToBottomMenuFragment() { + private fun navigateToHome() { findNavController().navigateSafe(LogInStagesFragmentDirections.toHomeFragment()) } - private fun navigateToSetupCirclesOrHome() { - findNavController().navigateSafe( - if (CirclesAppConfig.isSetupCirclesEnabled) - LogInStagesFragmentDirections.toSetupCirclesFragment() - else - LogInStagesFragmentDirections.toHomeFragment() - ) - } - private fun showDiscardDialog() { showDialog( titleResIdRes = R.string.discard_current_login_progress, diff --git a/auth/src/main/java/org/futo/circles/auth/feature/log_in/stages/LoginStagesDataSource.kt b/auth/src/main/java/org/futo/circles/auth/feature/log_in/stages/LoginStagesDataSource.kt index 15cae3d1ffa3fc409e96fce24572af654b46a632..f94e6f2528d4b2aad732b561c92f31706eb246ff 100644 --- a/auth/src/main/java/org/futo/circles/auth/feature/log_in/stages/LoginStagesDataSource.kt +++ b/auth/src/main/java/org/futo/circles/auth/feature/log_in/stages/LoginStagesDataSource.kt @@ -14,27 +14,24 @@ import org.futo.circles.core.extensions.Response import org.futo.circles.core.extensions.createResult import org.futo.circles.core.provider.MatrixInstanceProvider import org.futo.circles.core.provider.MatrixSessionProvider -import org.futo.circles.core.room.CoreSpacesTreeBuilder import org.matrix.android.sdk.api.auth.registration.RegistrationResult import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.util.JsonDict import javax.inject.Inject import javax.inject.Singleton -enum class LoginNavigationEvent { Main, SetupCircles, PassPhrase } +enum class LoginNavigationEvent { Main, PassPhrase } @Singleton class LoginStagesDataSource @Inject constructor( @ApplicationContext private val context: Context, private val restoreBackupDataSource: RestoreBackupDataSource, - private val coreSpacesTreeBuilder: CoreSpacesTreeBuilder, private val encryptionAlgorithmHelper: EncryptionAlgorithmHelper, private val createPassPhraseDataSource: CreatePassPhraseDataSource ) : BaseLoginStagesDataSource(context) { val loginNavigationLiveData = SingleEventLiveData<LoginNavigationEvent>() val passPhraseLoadingLiveData = restoreBackupDataSource.loadingLiveData - val spacesTreeLoadingLiveData = coreSpacesTreeBuilder.loadingLiveData val messageEventLiveData = SingleEventLiveData<Int>() override suspend fun performLoginStage( @@ -113,17 +110,12 @@ class LoginStagesDataSource @Inject constructor( private suspend fun handleRestoreResult(restoreResult: Response<Unit>): Response<Unit> { when (restoreResult) { is Response.Error -> loginNavigationLiveData.postValue(LoginNavigationEvent.PassPhrase) - is Response.Success -> createSpacesTreeIfNotExist() + is Response.Success -> navigateToMain() } return restoreResult } - suspend fun createSpacesTreeIfNotExist() { - val isCirclesCreated = coreSpacesTreeBuilder.isCirclesHierarchyCreated() - if (!isCirclesCreated) createResult { coreSpacesTreeBuilder.createCoreSpacesTree() } - loginNavigationLiveData.postValue( - if (isCirclesCreated) LoginNavigationEvent.Main - else LoginNavigationEvent.SetupCircles - ) + fun navigateToMain() { + loginNavigationLiveData.postValue(LoginNavigationEvent.Main) } } \ No newline at end of file diff --git a/auth/src/main/java/org/futo/circles/auth/feature/log_in/stages/LoginStagesViewModel.kt b/auth/src/main/java/org/futo/circles/auth/feature/log_in/stages/LoginStagesViewModel.kt index 2b98a27c77aa0a092b0b8e573f6e5c66332c2817..610bf135a5491f278f8e915eadf65cd604da49e4 100644 --- a/auth/src/main/java/org/futo/circles/auth/feature/log_in/stages/LoginStagesViewModel.kt +++ b/auth/src/main/java/org/futo/circles/auth/feature/log_in/stages/LoginStagesViewModel.kt @@ -17,7 +17,6 @@ class LoginStagesViewModel @Inject constructor( val restoreKeysLiveData = org.futo.circles.core.SingleEventLiveData<Response<Unit>>() val loginNavigationLiveData = loginStagesDataSource.loginNavigationLiveData val passPhraseLoadingLiveData = loginStagesDataSource.passPhraseLoadingLiveData - val spacesTreeLoadingLiveData = loginStagesDataSource.spacesTreeLoadingLiveData val messageEventLiveData = loginStagesDataSource.messageEventLiveData fun restoreBackupWithPassPhrase(passphrase: String) { @@ -41,7 +40,7 @@ class LoginStagesViewModel @Inject constructor( } fun onDoNotRestoreBackup() { - launchBg { loginStagesDataSource.createSpacesTreeIfNotExist() } + loginStagesDataSource.navigateToMain() } } \ No newline at end of file diff --git a/auth/src/main/java/org/futo/circles/auth/feature/pass_phrase/create/CreatePassPhraseDataSource.kt b/auth/src/main/java/org/futo/circles/auth/feature/pass_phrase/create/CreatePassPhraseDataSource.kt index 1a93ce63e0c0ee9ba74ea6fa6e8b0701a22f6178..145a87cc560062cfb1a744248644eb9b26e854bb 100644 --- a/auth/src/main/java/org/futo/circles/auth/feature/pass_phrase/create/CreatePassPhraseDataSource.kt +++ b/auth/src/main/java/org/futo/circles/auth/feature/pass_phrase/create/CreatePassPhraseDataSource.kt @@ -27,12 +27,7 @@ class CreatePassPhraseDataSource @Inject constructor( val loadingLiveData = MutableLiveData<LoadingData>() suspend fun createPassPhraseBackup() { - loadingLiveData.postValue( - LoadingData( - total = 0, - messageId = R.string.generating_recovery_key - ) - ) + loadingLiveData.postValue(LoadingData(messageId = R.string.generating_recovery_key)) val keyBackupPrivateKey = generateRandomPrivateKey() val backupCreationInfo = awaitCallback { keysBackupService.prepareKeysBackupVersion(keyBackupPrivateKey, it) @@ -49,7 +44,7 @@ class CreatePassPhraseDataSource @Inject constructor( } suspend fun changeBsSpekePassword4SKey() { - loadingLiveData.postValue(LoadingData(total = 0, messageId = R.string.creating_backup)) + loadingLiveData.postValue(LoadingData(messageId = R.string.creating_backup)) ssssDataSource.replaceBsSpeke4SKey() loadingLiveData.postValue(LoadingData(isLoading = false)) } diff --git a/auth/src/main/java/org/futo/circles/auth/feature/profile/setup/SetupProfileFragment.kt b/auth/src/main/java/org/futo/circles/auth/feature/profile/setup/SetupProfileFragment.kt index bc4330ed24c7398cc1b436940cfac027383b9e14..761dc679a9db9fb908c6981ecf8a1cb818640c07 100644 --- a/auth/src/main/java/org/futo/circles/auth/feature/profile/setup/SetupProfileFragment.kt +++ b/auth/src/main/java/org/futo/circles/auth/feature/profile/setup/SetupProfileFragment.kt @@ -10,7 +10,6 @@ import by.kirich1409.viewbindingdelegate.viewBinding import dagger.hilt.android.AndroidEntryPoint import org.futo.circles.auth.R import org.futo.circles.auth.databinding.FragmentSetupProfileBinding -import org.futo.circles.core.CirclesAppConfig import org.futo.circles.core.extensions.getText import org.futo.circles.core.extensions.navigateSafe import org.futo.circles.core.extensions.observeData @@ -35,7 +34,7 @@ class SetupProfileFragment : Fragment(R.layout.fragment_setup_profile), HasLoadi private fun setupViews() { with(binding) { - btnSkip.setOnClickListener { navigateToSetupCirclesOrHome() } + btnSkip.setOnClickListener { navigateToHome() } btnSave.setOnClickListener { startLoading(btnSave) viewModel.saveProfileInfo(tilDisplayName.getText()) @@ -62,17 +61,12 @@ class SetupProfileFragment : Fragment(R.layout.fragment_setup_profile), HasLoadi } viewModel.saveProfileResponseLiveData.observeResponse( this, - success = { navigateToSetupCirclesOrHome() } + success = { navigateToHome() } ) } - private fun navigateToSetupCirclesOrHome() { - findNavController().navigateSafe( - if (CirclesAppConfig.isSetupCirclesEnabled) - SetupProfileFragmentDirections.toSetupCirclesFragment() - else - SetupProfileFragmentDirections.toHomeFragment() - ) + private fun navigateToHome() { + findNavController().navigateSafe(SetupProfileFragmentDirections.toHomeFragment()) } private fun setSaveButtonEnabled() { diff --git a/auth/src/main/java/org/futo/circles/auth/feature/sign_up/SignUpDataSource.kt b/auth/src/main/java/org/futo/circles/auth/feature/sign_up/SignUpDataSource.kt index d7c75f5b7bc6b26dd0296196eb2fa22f2357c7d9..df076973c395c64e2a216cbbfff25325934c0c13 100644 --- a/auth/src/main/java/org/futo/circles/auth/feature/sign_up/SignUpDataSource.kt +++ b/auth/src/main/java/org/futo/circles/auth/feature/sign_up/SignUpDataSource.kt @@ -14,7 +14,6 @@ import org.futo.circles.core.extensions.createResult import org.futo.circles.core.provider.MatrixInstanceProvider import org.futo.circles.core.provider.MatrixSessionProvider import org.futo.circles.core.provider.PreferencesProvider -import org.futo.circles.core.room.CoreSpacesTreeBuilder import org.matrix.android.sdk.api.auth.registration.RegistrationResult import org.matrix.android.sdk.api.auth.registration.Stage import org.matrix.android.sdk.api.session.Session @@ -27,7 +26,6 @@ enum class SignUpNavigationEvents { TokenValidation, Subscription, AcceptTerm, V @Singleton class SignUpDataSource @Inject constructor( @ApplicationContext private val context: Context, - private val coreSpacesTreeBuilder: CoreSpacesTreeBuilder, private val createPassPhraseDataSource: CreatePassPhraseDataSource, private val preferencesProvider: PreferencesProvider ) { @@ -36,7 +34,6 @@ class SignUpDataSource @Inject constructor( val navigationLiveData = SingleEventLiveData<SignUpNavigationEvents>() val finishRegistrationLiveData = SingleEventLiveData<Response<Unit>>() val passPhraseLoadingLiveData = createPassPhraseDataSource.loadingLiveData - val spaceTreeLoadingLiveData = coreSpacesTreeBuilder.loadingLiveData val stagesToComplete = mutableListOf<Stage>() @@ -117,7 +114,6 @@ class SignUpDataSource @Inject constructor( MatrixSessionProvider.awaitForSessionStart(session) preferencesProvider.setShouldShowAllExplanations() createPassPhraseDataSource.createPassPhraseBackup() - coreSpacesTreeBuilder.createCoreSpacesTree() BSSpekeClientProvider.clear() } diff --git a/auth/src/main/java/org/futo/circles/auth/feature/sign_up/SignUpFragment.kt b/auth/src/main/java/org/futo/circles/auth/feature/sign_up/SignUpFragment.kt index bd780308449cc10cb08ff01bceba439192794929..e0a6a229aa011fce81cffac7cc2147255acb89ba 100644 --- a/auth/src/main/java/org/futo/circles/auth/feature/sign_up/SignUpFragment.kt +++ b/auth/src/main/java/org/futo/circles/auth/feature/sign_up/SignUpFragment.kt @@ -47,7 +47,7 @@ class SignUpFragment : Fragment(R.layout.fragment_sign_up), handleNavigation(it) } viewModel.finishRegistrationLiveData.observeResponse(this, - success = { navigateToSetupProfile() }, + success = { navigateToConfigureWorspace() }, error = { message -> showError(message) loadingDialog.dismiss() @@ -56,9 +56,6 @@ class SignUpFragment : Fragment(R.layout.fragment_sign_up), viewModel.passPhraseLoadingLiveData.observeData(this) { loadingDialog.handleLoading(it) } - viewModel.spaceTreeLoadingLiveData.observeData(this) { - loadingDialog.handleLoading(it) - } } @@ -96,8 +93,8 @@ class SignUpFragment : Fragment(R.layout.fragment_sign_up), } } - private fun navigateToSetupProfile() { - findNavController().navigateSafe(SignUpFragmentDirections.toSetupProfileFragment()) + private fun navigateToConfigureWorspace() { + findNavController().navigateSafe(SignUpFragmentDirections.toConfigureWorkspace()) } } \ No newline at end of file diff --git a/auth/src/main/java/org/futo/circles/auth/feature/sign_up/SignUpViewModel.kt b/auth/src/main/java/org/futo/circles/auth/feature/sign_up/SignUpViewModel.kt index e47ecf65446861a51ecc9c24d460040c09cb109a..039bc2140d3cb7fd01c5e9e704fb3e3cc87efc02 100644 --- a/auth/src/main/java/org/futo/circles/auth/feature/sign_up/SignUpViewModel.kt +++ b/auth/src/main/java/org/futo/circles/auth/feature/sign_up/SignUpViewModel.kt @@ -11,7 +11,6 @@ class SignUpViewModel @Inject constructor( val subtitleLiveData = datasource.subtitleLiveData val passPhraseLoadingLiveData = datasource.passPhraseLoadingLiveData - val spaceTreeLoadingLiveData = datasource.spaceTreeLoadingLiveData val finishRegistrationLiveData = datasource.finishRegistrationLiveData val navigationLiveData = datasource.navigationLiveData diff --git a/auth/src/main/java/org/futo/circles/auth/feature/workspace/ConfigureWorkspaceFragment.kt b/auth/src/main/java/org/futo/circles/auth/feature/workspace/ConfigureWorkspaceFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..071bc2ba0aea567ce2da51476a781778943ea9fa --- /dev/null +++ b/auth/src/main/java/org/futo/circles/auth/feature/workspace/ConfigureWorkspaceFragment.kt @@ -0,0 +1,96 @@ +package org.futo.circles.auth.feature.workspace + +import android.content.Context +import android.os.Bundle +import android.view.View +import androidx.core.os.bundleOf +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import androidx.navigation.fragment.findNavController +import androidx.recyclerview.widget.DividerItemDecoration +import by.kirich1409.viewbindingdelegate.viewBinding +import dagger.hilt.android.AndroidEntryPoint +import org.futo.circles.auth.R +import org.futo.circles.auth.databinding.FragmentConfigureWorkspaceBinding +import org.futo.circles.auth.feature.workspace.list.WorkspaceTasksListAdapter +import org.futo.circles.core.extensions.navigateSafe +import org.futo.circles.core.extensions.observeData +import org.futo.circles.core.extensions.observeResponse +import org.futo.circles.core.extensions.showError +import org.futo.circles.core.fragment.HasLoadingState + +@AndroidEntryPoint +class ConfigureWorkspaceFragment : Fragment(R.layout.fragment_configure_workspace), + HasLoadingState { + + override val fragment: Fragment = this + private val viewModel by viewModels<ConfigureWorkspaceViewModel>() + + private val binding by viewBinding(FragmentConfigureWorkspaceBinding::bind) + + private val tasksAdapter by lazy { + WorkspaceTasksListAdapter { viewModel.onOptionalTaskSelectionChanged(it) } + } + + private var configureWorkspaceListener: ConfigureWorkspaceListener? = null + + override fun onAttach(context: Context) { + super.onAttach(context) + configureWorkspaceListener = (parentFragment as? ConfigureWorkspaceListener) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setupViews() + setupObservers() + } + + private fun setupViews() { + with(binding) { + val shouldValidate = arguments?.getBoolean(SHOULD_VALIDATE) ?: false + toolbar.title = + getString(if (shouldValidate) R.string.validating_workspace else R.string.configure_workspace) + + if (shouldValidate) startLoading(btbConfigure) + + rvWorkspaceTasks.apply { + adapter = tasksAdapter + addItemDecoration(DividerItemDecoration(context, DividerItemDecoration.VERTICAL)) + } + btbConfigure.setOnClickListener { + startLoading(btbConfigure) + viewModel.createWorkspace() + } + } + } + + private fun setupObservers() { + viewModel.tasksLiveData.observeData(this) { + tasksAdapter.submitList(it) + } + viewModel.workspaceResultLiveData.observeResponse(this, + success = { + configureWorkspaceListener?.onWorkspaceConfigured() ?: kotlin.run { + findNavController() + .navigateSafe(ConfigureWorkspaceFragmentDirections.toSetupProfileFragment()) + } + }, + error = { + showError(it) + binding.btbConfigure.setText(getString(R.string.retry)) + }) + viewModel.validateWorkspaceResultLiveData.observeResponse(this, + success = { configureWorkspaceListener?.onWorkspaceConfigured() }, + error = { + binding.toolbar.title = getString(R.string.configure_workspace) + } + ) + } + + companion object { + const val SHOULD_VALIDATE = "should_validate" + fun create(shouldValidate: Boolean) = ConfigureWorkspaceFragment().apply { + arguments = bundleOf(SHOULD_VALIDATE to shouldValidate) + } + } +} diff --git a/auth/src/main/java/org/futo/circles/auth/feature/workspace/ConfigureWorkspaceListener.kt b/auth/src/main/java/org/futo/circles/auth/feature/workspace/ConfigureWorkspaceListener.kt new file mode 100644 index 0000000000000000000000000000000000000000..62e6b2d453f55b4828746d879df8c1c5799ee0be --- /dev/null +++ b/auth/src/main/java/org/futo/circles/auth/feature/workspace/ConfigureWorkspaceListener.kt @@ -0,0 +1,6 @@ +package org.futo.circles.auth.feature.workspace + +interface ConfigureWorkspaceListener { + fun onWorkspaceConfigured() + +} \ No newline at end of file diff --git a/auth/src/main/java/org/futo/circles/auth/feature/workspace/ConfigureWorkspaceViewModel.kt b/auth/src/main/java/org/futo/circles/auth/feature/workspace/ConfigureWorkspaceViewModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..5725dc656df6a57c59580c3771ae1d2ca9e3c5f8 --- /dev/null +++ b/auth/src/main/java/org/futo/circles/auth/feature/workspace/ConfigureWorkspaceViewModel.kt @@ -0,0 +1,103 @@ +package org.futo.circles.auth.feature.workspace + +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.ViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import org.futo.circles.auth.feature.workspace.data_source.ConfigureWorkspaceDataSource +import org.futo.circles.auth.feature.workspace.data_source.WorkspaceTasksProvider +import org.futo.circles.auth.model.MandatoryWorkspaceTask +import org.futo.circles.auth.model.OptionalWorkspaceTask +import org.futo.circles.core.SingleEventLiveData +import org.futo.circles.core.extensions.Response +import org.futo.circles.core.extensions.createResult +import org.futo.circles.core.extensions.launchBg +import org.futo.circles.core.model.TaskStatus +import javax.inject.Inject + +@HiltViewModel +class ConfigureWorkspaceViewModel @Inject constructor( + savedStateHandle: SavedStateHandle, + workspaceTasksProvider: WorkspaceTasksProvider, + private val workspaceDataSource: ConfigureWorkspaceDataSource +) : ViewModel() { + + private val shouldValidate = + savedStateHandle.get<Boolean>(ConfigureWorkspaceFragment.SHOULD_VALIDATE) ?: false + val tasksLiveData = MutableLiveData( + if (shouldValidate) workspaceTasksProvider.getMandatoryTasks() + else workspaceTasksProvider.getFullTasksList() + ) + val workspaceResultLiveData = SingleEventLiveData<Response<Unit>>() + val validateWorkspaceResultLiveData = SingleEventLiveData<Response<Unit>>() + + init { + if (shouldValidate) validateWorkspace() + } + + private fun validateWorkspace() = launchBg { + val tasks = tasksLiveData.value?.toMutableList() ?: mutableListOf() + var hasError = false + tasks.forEachIndexed { i, item -> + updateTaskStatus(i, TaskStatus.RUNNING) + when (createResult { workspaceDataSource.validate(item.room) }) { + is Response.Error -> { + hasError = true + updateTaskStatus(i, TaskStatus.FAILED) + } + + is Response.Success -> updateTaskStatus(i, TaskStatus.SUCCESS) + } + } + validateWorkspaceResultLiveData.postValue( + if (hasError) Response.Error("") else Response.Success(Unit) + ) + } + + fun createWorkspace() = launchBg { + val tasks = tasksLiveData.value?.toMutableList() ?: mutableListOf() + tasks.forEachIndexed { i, item -> + (item as? OptionalWorkspaceTask)?.let { if (!it.isSelected) return@forEachIndexed } + if (item.status == TaskStatus.SUCCESS) return@forEachIndexed + + updateTaskStatus(i, TaskStatus.RUNNING) + when (val result = createResult { workspaceDataSource.performCreateOrFix(item.room) }) { + is Response.Error -> { + updateTaskStatus(i, TaskStatus.FAILED) + workspaceResultLiveData.postValue(result) + return@launchBg + } + + is Response.Success -> updateTaskStatus(i, TaskStatus.SUCCESS) + } + } + workspaceResultLiveData.postValue(Response.Success(Unit)) + } + + fun onOptionalTaskSelectionChanged(optionalWorkspaceTask: OptionalWorkspaceTask) { + val newList = tasksLiveData.value?.toMutableList()?.apply { + val index = indexOf(optionalWorkspaceTask).takeIf { it != -1 } ?: return + add(index, optionalWorkspaceTask.copy(isSelected = !optionalWorkspaceTask.isSelected)) + remove(optionalWorkspaceTask) + } + tasksLiveData.value = newList + } + + private suspend fun updateTaskStatus(index: Int, status: TaskStatus) { + val tasks = tasksLiveData.value?.toMutableList() ?: mutableListOf() + val task = tasks.getOrNull(index) ?: return + val newList = tasks.toMutableList().apply { + add( + index, when (task) { + is MandatoryWorkspaceTask -> task.copy(status = status) + is OptionalWorkspaceTask -> task.copy(status = status) + } + ) + remove(task) + } + withContext(Dispatchers.Main) { tasksLiveData.value = newList } + } + +} \ No newline at end of file diff --git a/auth/src/main/java/org/futo/circles/auth/feature/workspace/WorkspaceDialogFragment.kt b/auth/src/main/java/org/futo/circles/auth/feature/workspace/WorkspaceDialogFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..388f0dc0cf690353e6e6d14a1c9c4410484e5d5c --- /dev/null +++ b/auth/src/main/java/org/futo/circles/auth/feature/workspace/WorkspaceDialogFragment.kt @@ -0,0 +1,32 @@ +package org.futo.circles.auth.feature.workspace + +import android.os.Bundle +import android.view.View +import dagger.hilt.android.AndroidEntryPoint +import org.futo.circles.auth.R +import org.futo.circles.auth.databinding.DialogFragmentWorkspaceBinding +import org.futo.circles.core.extensions.showSuccess +import org.futo.circles.core.fragment.BaseFullscreenDialogFragment + +@AndroidEntryPoint +class WorkspaceDialogFragment : + BaseFullscreenDialogFragment(DialogFragmentWorkspaceBinding::inflate), + ConfigureWorkspaceListener { + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + isCancelable = false + addConfigureWorkspaceFragment() + } + + private fun addConfigureWorkspaceFragment() { + childFragmentManager.beginTransaction() + .replace(R.id.lContainer, ConfigureWorkspaceFragment.create(true)) + .commitAllowingStateLoss() + } + + override fun onWorkspaceConfigured() { + showSuccess(getString(R.string.workspace_configured)) + dismiss() + } +} \ No newline at end of file diff --git a/auth/src/main/java/org/futo/circles/auth/feature/workspace/data_source/ConfigureWorkspaceDataSource.kt b/auth/src/main/java/org/futo/circles/auth/feature/workspace/data_source/ConfigureWorkspaceDataSource.kt new file mode 100644 index 0000000000000000000000000000000000000000..8c8d1f2b423d70be568d297200ad74bb58becc05 --- /dev/null +++ b/auth/src/main/java/org/futo/circles/auth/feature/workspace/data_source/ConfigureWorkspaceDataSource.kt @@ -0,0 +1,105 @@ +package org.futo.circles.auth.feature.workspace.data_source + +import kotlinx.coroutines.delay +import org.futo.circles.core.model.CirclesRoom +import org.futo.circles.core.provider.MatrixSessionProvider +import org.futo.circles.core.room.CreateRoomDataSource +import org.futo.circles.core.room.RoomRelationsBuilder +import org.futo.circles.core.utils.getJoinedRoomById +import org.futo.circles.core.workspace.SpacesTreeAccountDataSource +import org.matrix.android.sdk.api.session.room.Room +import org.matrix.android.sdk.api.session.room.model.Membership +import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams +import javax.inject.Inject + +class ConfigureWorkspaceDataSource @Inject constructor( + private val createRoomDataSource: CreateRoomDataSource, + private val spacesTreeAccountDataSource: SpacesTreeAccountDataSource, + private val roomRelationsBuilder: RoomRelationsBuilder +) { + + suspend fun performCreateOrFix(room: CirclesRoom) { + var roomId = addIdToAccountDataIfRoomExistWithTag(room) + if (roomId == null) roomId = getJoinedRoomIdFromAccountData(room) + if (roomId == null) createRoomWithAccountDataRecordIfNeed(room) + else { + try { + getJoinedRoomById(roomId)?.let { validateRelations(room.parentAccountDataKey, it) } + } catch (_: Exception) { + val parentRoomId = + room.parentAccountDataKey?.let { spacesTreeAccountDataSource.getRoomIdByKey(it) } + parentRoomId?.let { roomRelationsBuilder.setRelations(roomId, parentRoomId) } + } + } + } + + fun validate(room: CirclesRoom) { + val accountDataKey = room.accountDataKey ?: return + val roomId = spacesTreeAccountDataSource.getRoomIdByKey(accountDataKey) + ?: throw IllegalArgumentException("No account data record for key $accountDataKey") + val joinedRoom = getJoinedRoomById(roomId) + ?: throw IllegalArgumentException("No joined room for id $roomId found") + validateRelations(room.parentAccountDataKey, joinedRoom) + } + + private fun validateRelations(parentAccountDataKey: String?, joinedRoom: Room) { + val parentKey = parentAccountDataKey ?: return + val parentRoomId = + spacesTreeAccountDataSource.getRoomIdByKey(parentKey) ?: throw IllegalArgumentException( + "No account data record for parent with key $parentKey" + ) + val joinedParentRoom = getJoinedRoomById(parentRoomId) + ?: throw IllegalArgumentException("No joined parent room for id $parentKey found") + + val childHasRelationToParent = joinedRoom.asSpace() + ?.spaceSummary()?.spaceParents?.mapNotNull { it.parentId } + ?.contains(parentRoomId) == true + + if (!childHasRelationToParent) + throw IllegalArgumentException("Missing child to parent relations") + + val parentHasRelationToChild = joinedParentRoom.asSpace() + ?.spaceSummary()?.spaceChildren?.map { it.childRoomId } + ?.contains(joinedRoom.roomId) == true + + if (!parentHasRelationToChild) + throw IllegalArgumentException("Missing parent to child relations") + } + + private suspend fun addIdToAccountDataIfRoomExistWithTag(room: CirclesRoom): String? { + val tag = room.getTag() ?: return null + val key = room.accountDataKey ?: return null + val roomId = getJoinedRoomIdByTag(tag) ?: return null + spacesTreeAccountDataSource.updateSpacesConfigAccountData(key, roomId) + return roomId + } + + private fun getJoinedRoomIdByTag(tag: String): String? { + val session = MatrixSessionProvider.currentSession ?: return null + return session.roomService().getRoomSummaries(roomSummaryQueryParams { + excludeType = null + memberships = listOf(Membership.JOIN) + }).firstOrNull { it.hasTag(tag) }?.roomId + } + + private fun getJoinedRoomIdFromAccountData(room: CirclesRoom): String? { + val key = room.accountDataKey ?: return null + val roomId = spacesTreeAccountDataSource.getRoomIdByKey(key) ?: return null + getJoinedRoomById(roomId) ?: return null + return roomId + } + + private suspend fun createRoomWithAccountDataRecordIfNeed(room: CirclesRoom): String { + val roomId = createRoomDataSource.createRoom(room) + room.accountDataKey?.let { key -> + spacesTreeAccountDataSource.updateSpacesConfigAccountData(key, roomId) + } + delay(CREATE_ROOM_DELAY) + return roomId + } + + private companion object { + private const val CREATE_ROOM_DELAY = 1000L + } + +} \ No newline at end of file diff --git a/auth/src/main/java/org/futo/circles/auth/feature/workspace/data_source/WorkspaceTasksProvider.kt b/auth/src/main/java/org/futo/circles/auth/feature/workspace/data_source/WorkspaceTasksProvider.kt new file mode 100644 index 0000000000000000000000000000000000000000..928e884f90a329e29ef27188600c0f751a27b934 --- /dev/null +++ b/auth/src/main/java/org/futo/circles/auth/feature/workspace/data_source/WorkspaceTasksProvider.kt @@ -0,0 +1,49 @@ +package org.futo.circles.auth.feature.workspace.data_source + +import org.futo.circles.auth.R +import org.futo.circles.auth.model.MandatoryWorkspaceTask +import org.futo.circles.auth.model.OptionalWorkspaceTask +import org.futo.circles.auth.model.WorkspaceTask +import org.futo.circles.core.model.Circle +import org.futo.circles.core.model.CirclesSpace +import org.futo.circles.core.model.Gallery +import org.futo.circles.core.model.GroupsSpace +import org.futo.circles.core.model.PeopleSpace +import org.futo.circles.core.model.PhotosSpace +import org.futo.circles.core.model.RootSpace +import org.futo.circles.core.model.SharedCirclesSpace +import javax.inject.Inject + +class WorkspaceTasksProvider @Inject constructor() { + + fun getFullTasksList() = mutableListOf<WorkspaceTask>().apply { + addAll(getMandatoryTasks()) + addAll(getOptionalTasks()) + } + + fun getMandatoryTasks() = listOf( + MandatoryWorkspaceTask(RootSpace(), R.string.root_space_description), + MandatoryWorkspaceTask(CirclesSpace(), R.string.circles_space_description), + MandatoryWorkspaceTask(GroupsSpace(), R.string.groups_space_description), + MandatoryWorkspaceTask(PhotosSpace(), R.string.galleries_space_description), + MandatoryWorkspaceTask(PeopleSpace(), R.string.people_space_description), + MandatoryWorkspaceTask(SharedCirclesSpace(), R.string.profile_space_description) + ) + + private fun getOptionalTasks() = listOf( + OptionalWorkspaceTask( + Gallery(nameId = org.futo.circles.core.R.string.photos), + R.string.photos_room_description + ), + OptionalWorkspaceTask( + Circle(nameId = R.string.friends), + R.string.friends_circle_description + ), + OptionalWorkspaceTask(Circle(nameId = R.string.family), R.string.family_circle_description), + OptionalWorkspaceTask( + Circle(nameId = R.string.community), + R.string.community_circle_description + ) + ) + +} \ No newline at end of file diff --git a/auth/src/main/java/org/futo/circles/auth/feature/workspace/list/WorkspaceTaskViewHolder.kt b/auth/src/main/java/org/futo/circles/auth/feature/workspace/list/WorkspaceTaskViewHolder.kt new file mode 100644 index 0000000000000000000000000000000000000000..711a3287a379b0421f338cc6038f2996611e6b7f --- /dev/null +++ b/auth/src/main/java/org/futo/circles/auth/feature/workspace/list/WorkspaceTaskViewHolder.kt @@ -0,0 +1,97 @@ +package org.futo.circles.auth.feature.workspace.list + +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.ProgressBar +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.RecyclerView +import org.futo.circles.auth.R +import org.futo.circles.auth.databinding.ListItemMandatoryWorkspaceTaskBinding +import org.futo.circles.auth.databinding.ListItemOptionalWorkspaceTaskBinding +import org.futo.circles.core.extensions.gone +import org.futo.circles.core.extensions.onClick +import org.futo.circles.core.extensions.visible +import org.futo.circles.core.list.ViewBindingHolder +import org.futo.circles.core.list.context +import org.futo.circles.auth.model.OptionalWorkspaceTask +import org.futo.circles.core.model.TaskStatus +import org.futo.circles.auth.model.WorkspaceTask + + +abstract class WorkspaceTaskViewHolder(view: View) : RecyclerView.ViewHolder(view) { + abstract fun bind(data: WorkspaceTask) + + protected fun bindStatus(status: TaskStatus, ivStatus: ImageView, vTaskProgress: ProgressBar) { + when (status) { + TaskStatus.RUNNING -> { + ivStatus.gone() + vTaskProgress.visible() + } + + TaskStatus.IDLE -> { + ivStatus.gone() + vTaskProgress.gone() + } + + else -> { + vTaskProgress.gone() + ivStatus.apply { + visible() + setImageResource( + if (status == TaskStatus.FAILED) org.futo.circles.core.R.drawable.ic_error + else org.futo.circles.core.R.drawable.ic_check_circle + ) + setColorFilter( + ContextCompat.getColor( + context, + if (status == TaskStatus.FAILED) R.color.red + else R.color.blue + ) + ) + } + } + } + } + +} + +class MandatoryWorkspaceTaskViewHolder( + parent: ViewGroup, +) : WorkspaceTaskViewHolder(inflate(parent, ListItemMandatoryWorkspaceTaskBinding::inflate)) { + + private companion object : ViewBindingHolder + + private val binding = baseBinding as ListItemMandatoryWorkspaceTaskBinding + + override fun bind(data: WorkspaceTask) { + with(binding) { + data.room.nameId?.let { tvName.text = context.getString(it) } + tvMessage.text = context.getString(data.descriptionResId) + bindStatus(data.status, ivTaskStatus, taskProgress) + } + } +} + +class OptionalWorkspaceTaskViewHolder( + parent: ViewGroup, + onItemClicked: (Int) -> Unit +) : WorkspaceTaskViewHolder(inflate(parent, ListItemOptionalWorkspaceTaskBinding::inflate)) { + + private companion object : ViewBindingHolder + + private val binding = baseBinding as ListItemOptionalWorkspaceTaskBinding + + init { + onClick(binding.rootItem) { onItemClicked(it) } + } + + override fun bind(data: WorkspaceTask) { + with(binding.lTask) { + data.room.nameId?.let { tvName.text = context.getString(it) } + tvMessage.text = context.getString(data.descriptionResId) + bindStatus(data.status, ivTaskStatus, taskProgress) + } + binding.taskCheck.isChecked = (data as? OptionalWorkspaceTask)?.isSelected ?: false + } +} \ No newline at end of file diff --git a/auth/src/main/java/org/futo/circles/auth/feature/workspace/list/WorkspaceTasksListAdapter.kt b/auth/src/main/java/org/futo/circles/auth/feature/workspace/list/WorkspaceTasksListAdapter.kt new file mode 100644 index 0000000000000000000000000000000000000000..1c3ab190243c7d6b400f361de2a03643b6171890 --- /dev/null +++ b/auth/src/main/java/org/futo/circles/auth/feature/workspace/list/WorkspaceTasksListAdapter.kt @@ -0,0 +1,40 @@ +package org.futo.circles.auth.feature.workspace.list + +import android.view.ViewGroup +import org.futo.circles.core.list.BaseRvAdapter +import org.futo.circles.auth.model.MandatoryWorkspaceTask +import org.futo.circles.auth.model.OptionalWorkspaceTask +import org.futo.circles.auth.model.WorkspaceTask + +private enum class WorkspaceTaskViewType { Mandatory, Optional } + +class WorkspaceTasksListAdapter( + private val onOptionalItemClicked: (OptionalWorkspaceTask) -> Unit +) : BaseRvAdapter<WorkspaceTask, WorkspaceTaskViewHolder>(DefaultIdEntityCallback()) { + + override fun getItemViewType(position: Int): Int = when (getItem(position)) { + is MandatoryWorkspaceTask -> WorkspaceTaskViewType.Mandatory.ordinal + is OptionalWorkspaceTask -> WorkspaceTaskViewType.Optional.ordinal + } + + override fun onCreateViewHolder( + parent: ViewGroup, + viewType: Int + ) = when (WorkspaceTaskViewType.values()[viewType]) { + WorkspaceTaskViewType.Mandatory -> MandatoryWorkspaceTaskViewHolder(parent = parent) + + WorkspaceTaskViewType.Optional -> OptionalWorkspaceTaskViewHolder( + parent = parent, + onItemClicked = { position -> + (getItem(position) as? OptionalWorkspaceTask)?.let { + onOptionalItemClicked.invoke(it) + } + } + ) + } + + override fun onBindViewHolder(holder: WorkspaceTaskViewHolder, position: Int) { + holder.bind(getItem(position)) + } + +} \ No newline at end of file diff --git a/auth/src/main/java/org/futo/circles/auth/model/WorkspaceTask.kt b/auth/src/main/java/org/futo/circles/auth/model/WorkspaceTask.kt new file mode 100644 index 0000000000000000000000000000000000000000..c6815d089c3d00f89b8bc0db9933ca2c5043baa8 --- /dev/null +++ b/auth/src/main/java/org/futo/circles/auth/model/WorkspaceTask.kt @@ -0,0 +1,29 @@ +package org.futo.circles.auth.model + +import org.futo.circles.core.list.IdEntity +import org.futo.circles.core.model.CirclesRoom +import org.futo.circles.core.model.TaskStatus + +sealed class WorkspaceTask( + open val room: CirclesRoom, + open val descriptionResId: Int, + open val status: TaskStatus +) : IdEntity<Int> + + +data class MandatoryWorkspaceTask( + override val room: CirclesRoom, + override val descriptionResId: Int, + override val status: TaskStatus = TaskStatus.IDLE +) : WorkspaceTask(room, descriptionResId, status) { + override val id: Int = descriptionResId +} + +data class OptionalWorkspaceTask( + override val room: CirclesRoom, + override val descriptionResId: Int, + override val status: TaskStatus = TaskStatus.IDLE, + val isSelected: Boolean = true +) : WorkspaceTask(room, descriptionResId, status) { + override val id: Int = descriptionResId +} \ No newline at end of file diff --git a/auth/src/main/res/layout/dialog_fragment_workspace.xml b/auth/src/main/res/layout/dialog_fragment_workspace.xml new file mode 100644 index 0000000000000000000000000000000000000000..1b88477e231734b97709bd709e9eef02929cd74b --- /dev/null +++ b/auth/src/main/res/layout/dialog_fragment_workspace.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/lContainer" + android:layout_width="match_parent" + android:layout_height="match_parent" /> \ No newline at end of file diff --git a/auth/src/main/res/layout/fragment_configure_workspace.xml b/auth/src/main/res/layout/fragment_configure_workspace.xml new file mode 100644 index 0000000000000000000000000000000000000000..7ad151308cfa272c72be76d654cd29358a6ee5c6 --- /dev/null +++ b/auth/src/main/res/layout/fragment_configure_workspace.xml @@ -0,0 +1,79 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <com.google.android.material.appbar.MaterialToolbar + android:id="@+id/toolbar" + android:layout_width="0dp" + android:layout_height="?attr/actionBarSize" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:title="@string/configure_workspace" + app:titleCentered="true" /> + + <View + android:id="@+id/toolbarDivider" + android:layout_width="0dp" + android:layout_height="@dimen/divider_height" + android:background="@color/divider_color" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/toolbar" /> + + <TextView + android:id="@+id/tvMessage" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:gravity="center_horizontal" + android:text="@string/setup_workspace_message" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/toolbarDivider" /> + + <View + android:id="@+id/messageDivider" + android:layout_width="0dp" + android:layout_height="@dimen/divider_height" + android:layout_marginTop="8dp" + android:background="@color/divider_color" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/tvMessage" /> + + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/rvWorkspaceTasks" + android:layout_width="0dp" + android:layout_height="0dp" + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" + app:layout_constraintBottom_toTopOf="@id/buttonDivider" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/messageDivider" /> + + <View + android:id="@+id/buttonDivider" + android:layout_width="0dp" + android:layout_height="@dimen/divider_height" + android:layout_marginBottom="8dp" + android:background="@color/divider_color" + app:layout_constraintBottom_toTopOf="@id/btbConfigure" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" /> + + <org.futo.circles.core.view.LoadingButton + android:id="@+id/btbConfigure" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:layout_marginHorizontal="36dp" + android:layout_marginBottom="16dp" + android:text="@string/configure" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" /> + +</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/auth/src/main/res/layout/list_item_mandatory_workspace_task.xml b/auth/src/main/res/layout/list_item_mandatory_workspace_task.xml new file mode 100644 index 0000000000000000000000000000000000000000..84a748e6971714c3bd19bf2782c22756d5dbba62 --- /dev/null +++ b/auth/src/main/res/layout/list_item_mandatory_workspace_task.xml @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout 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:id="@+id/lRoot" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingHorizontal="8dp" + android:paddingVertical="4dp"> + + + <TextView + android:id="@+id/tvName" + style="@style/body" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginEnd="36dp" + android:ellipsize="end" + android:lines="1" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:text="Android01" /> + + <TextView + android:id="@+id/tvMessage" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginEnd="36dp" + android:ellipsize="end" + android:maxLines="4" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/tvName" + tools:text="Android01" /> + + <ProgressBar + android:id="@+id/taskProgress" + android:layout_width="24dp" + android:layout_height="24dp" + app:layout_constraintBottom_toBottomOf="@id/tvMessage" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <ImageView + android:id="@+id/ivTaskStatus" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/ic_check_circle" + android:visibility="gone" + app:layout_constraintBottom_toBottomOf="@id/tvMessage" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:tint="@color/blue" + tools:visibility="visible" /> + +</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/auth/src/main/res/layout/list_item_optional_workspace_task.xml b/auth/src/main/res/layout/list_item_optional_workspace_task.xml new file mode 100644 index 0000000000000000000000000000000000000000..249fa5323d43f9c2689683cef35811244a8a239b --- /dev/null +++ b/auth/src/main/res/layout/list_item_optional_workspace_task.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/rootItem" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="?selectableItemBackground" + android:clickable="true" + android:focusable="true"> + + + <com.google.android.material.checkbox.MaterialCheckBox + android:id="@+id/taskCheck" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:clickable="false" + android:padding="-3dp" + android:focusable="false" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + + <include + android:id="@+id/lTask" + layout="@layout/list_item_mandatory_workspace_task" + android:layout_width="0dp" + android:layout_height="wrap_content" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@id/taskCheck" /> + +</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/auth/src/main/res/layout/list_item_setup_circle.xml b/auth/src/main/res/layout/list_item_setup_circle.xml deleted file mode 100644 index 06ae73afb675c6ee4b13666cc4170688ebe354ab..0000000000000000000000000000000000000000 --- a/auth/src/main/res/layout/list_item_setup_circle.xml +++ /dev/null @@ -1,54 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<androidx.constraintlayout.widget.ConstraintLayout 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="wrap_content" - android:background="?selectableItemBackground" - android:clickable="true" - android:focusable="true" - android:padding="4dp"> - - - <com.google.android.material.imageview.ShapeableImageView - android:id="@+id/ivCircleCover" - android:layout_width="@dimen/group_icon_size" - android:layout_height="@dimen/group_icon_size" - android:scaleType="centerCrop" - android:src="@drawable/add_image_placeholder" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" - app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.App.GroupIconRadius" /> - - <TextView - android:id="@+id/tvCircleName" - style="@style/title2" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:ellipsize="end" - android:gravity="center" - android:lines="1" - app:layout_constraintBottom_toTopOf="@id/tvUserName" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toEndOf="@id/ivCircleCover" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintVertical_chainStyle="packed" - tools:text="texsdt" /> - - <TextView - android:id="@+id/tvUserName" - style="@style/subheadline" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_marginTop="4dp" - android:ellipsize="end" - android:gravity="center" - android:lines="1" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="@id/tvCircleName" - app:layout_constraintTop_toBottomOf="@id/tvCircleName" - tools:text="texsdt" /> - -</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/auth/src/main/res/navigation/nav_graph_auth.xml b/auth/src/main/res/navigation/nav_graph_auth.xml index 130ebbc3140b4318758efaf5e6dbf5659dfdd311..70937bba43d1467a34a17b41f04db31465c5ffb6 100644 --- a/auth/src/main/res/navigation/nav_graph_auth.xml +++ b/auth/src/main/res/navigation/nav_graph_auth.xml @@ -32,11 +32,6 @@ app:destination="@id/homeFragment" app:popUpTo="@id/logInFragment" app:popUpToInclusive="true" /> - <action - android:id="@+id/to_setupCirclesFragment" - app:destination="@id/setupCirclesFragment" - app:popUpTo="@id/logInFragment" - app:popUpToInclusive="true" /> </fragment> <fragment android:id="@+id/signUpFragment" @@ -44,8 +39,8 @@ android:label="Sign up" tools:layout="@layout/fragment_sign_up"> <action - android:id="@+id/to_setupProfileFragment" - app:destination="@id/setupProfileFragment" + android:id="@+id/to_ConfigureWorkspace" + app:destination="@id/configureWorkspaceFragment" app:popUpTo="@id/logInFragment" app:popUpToInclusive="true" /> </fragment> @@ -54,15 +49,21 @@ android:name="org.futo.circles.auth.feature.profile.setup.SetupProfileFragment" android:label="SetupProfileFragment" tools:layout="@layout/fragment_setup_profile"> - <action - android:id="@+id/to_setupCirclesFragment" - app:destination="@id/setupCirclesFragment" - app:popUpTo="@id/setupProfileFragment" - app:popUpToInclusive="true" /> + <action android:id="@+id/to_homeFragment" app:destination="@id/homeFragment" app:popUpTo="@id/setupProfileFragment" app:popUpToInclusive="true" /> </fragment> + <fragment + android:id="@+id/configureWorkspaceFragment" + android:name="org.futo.circles.auth.feature.workspace.ConfigureWorkspaceFragment" + tools:layout="@layout/fragment_configure_workspace"> + <action + android:id="@+id/to_setupProfileFragment" + app:destination="@id/setupProfileFragment" + app:popUpTo="@id/configureWorkspaceFragment" + app:popUpToInclusive="true" /> + </fragment> </navigation> diff --git a/auth/src/main/res/values/ids.xml b/auth/src/main/res/values/ids.xml index a3af135fe696c984e82c231d67b9955a9ccac20f..fdc7badf4aca669f2de11019221d4254bc9cf6b4 100644 --- a/auth/src/main/res/values/ids.xml +++ b/auth/src/main/res/values/ids.xml @@ -1,5 +1,4 @@ <?xml version="1.0" encoding="utf-8"?> <resources> <item name="homeFragment" type="id" /> - <item name="setupCirclesFragment" type="id" /> </resources> \ No newline at end of file diff --git a/auth/src/main/res/values/strings.xml b/auth/src/main/res/values/strings.xml index 8f380577d5c6dcc0a5d2f470f407da6becb97377..d8fbe864450d30a3ef00547a89d50bf6afc032b3 100644 --- a/auth/src/main/res/values/strings.xml +++ b/auth/src/main/res/values/strings.xml @@ -123,6 +123,27 @@ <string name="got_it">Got it</string> <string name="groups">Groups</string> <string name="circles">Circles</string> + <string name="create">Create</string> + <string name="friends">Friends</string> + <string name="family">Family</string> + <string name="community">Community</string> + <string name="retry">Retry</string> + <string name="workspace_configured">Workspace configured</string> + <string name="validating_workspace">Validating workspace</string> + <string name="configure_workspace">Configure workspace</string> + <string name="setup_workspace_message">In order to use app we needs to configure your workspace. \nWe will create root spaces listed below and setup all the necessary relations between them.</string> + <string name="root_space_description">Root space of workspace hierarchy</string> + <string name="groups_space_description">Space which will contain all the Groups</string> + <string name="circles_space_description">Space which will contain all the Circles</string> + <string name="galleries_space_description">Space which will contain all the Galleries</string> + <string name="people_space_description">Space which will contain all the connected users</string> + <string name="profile_space_description">Space which will contain all your public Circles. Other users will be able to ask to join this space to follow you</string> + <string name="photos_room_description">Optional: Photos gallery room for your media. You will be able to create it anytime</string> + <string name="friends_circle_description">Optional: Circle to follow your friends timelines. You will be able to create it anytime</string> + <string name="family_circle_description">Optional: Circle to follow your family members timelines. You will be able to create it anytime</string> + <string name="community_circle_description">Optional: Circle to follow other people timelines. You will be able to create it anytime</string> + + <string name="circle_explanation"><![CDATA[Tip: A <b>circle</b> works like a secure, private version of Facebook or Twitter. Everyone posts to their own timeline, and you see posts from all the timelines that you\'re following. <br/><br/>A circle is a good way to share things with lots of people who don\'t all know each other, but they all know you. <br/><br/>For example, think about all the aunts and uncles and cousins from the different sides of your family. @@ -132,6 +153,7 @@ Or, think about all of your friends across all of the places you\'ve ever lived. <br/><br/>Everyone in the group posts to the same timeline, and everyone in the group can see every post. <br/><br/>For example, you might want to create a group for your book club, or your sports team, or your scout troop. <br/><br/>If you want to share with lots of different people who <i>don\'t</i> all know each other, then you should invite those people to follow you in a <b>Circle</b> instead.]]></string> + <string name="configure">Configure</string> <plurals name="days"> <item quantity="one">%1$d day</item> diff --git a/core/src/main/java/org/futo/circles/core/CirclesAppConfig.kt b/core/src/main/java/org/futo/circles/core/CirclesAppConfig.kt index 9e3cc66bccf97de53dc1418dc4c2f88953080ac8..25844cca32f78c621fa4ab64f247cb2929358afd 100644 --- a/core/src/main/java/org/futo/circles/core/CirclesAppConfig.kt +++ b/core/src/main/java/org/futo/circles/core/CirclesAppConfig.kt @@ -28,9 +28,6 @@ object CirclesAppConfig { var isRageshakeEnabled = false private set - var isSetupCirclesEnabled = true - private set - data class Initializer( private var appId: String? = null, private var version: String? = null, @@ -40,8 +37,7 @@ object CirclesAppConfig { private var euDomain: String? = null, private var subscriptionEnabled: Boolean = false, private var mediaBackupEnabled: Boolean = false, - private var rageshakeEnabled: Boolean = false, - private var setupCirclesEnabled: Boolean = true + private var rageshakeEnabled: Boolean = false ) { fun buildConfigInfo(appId: String, version: String, flavour: String = "empty") = @@ -64,8 +60,6 @@ object CirclesAppConfig { fun isRageshakeEnabled(isEnabled: Boolean) = apply { this.rageshakeEnabled = isEnabled } - fun isSetupCirclesEnabled(isEnabled: Boolean) = - apply { this.setupCirclesEnabled = isEnabled } fun init() { CirclesAppConfig.appId = appId?.takeIf { it.isNotEmpty() } @@ -89,7 +83,6 @@ object CirclesAppConfig { isSubscriptionsEnabled = subscriptionEnabled isMediaBackupEnabled = mediaBackupEnabled isRageshakeEnabled = rageshakeEnabled - isSetupCirclesEnabled = setupCirclesEnabled } } diff --git a/core/src/main/java/org/futo/circles/core/Constants.kt b/core/src/main/java/org/futo/circles/core/Constants.kt index 39e98ad311819411e420ae7cb2d9ef279010df8a..c2f77bf1f789f91143e0a1892773c554346a51c0 100644 --- a/core/src/main/java/org/futo/circles/core/Constants.kt +++ b/core/src/main/java/org/futo/circles/core/Constants.kt @@ -3,9 +3,6 @@ package org.futo.circles.core import org.futo.circles.core.provider.MatrixSessionProvider const val FILE_PROVIDER_AUTHORITY_EXTENSION = ".provider" -const val CREATE_ROOM_DELAY = 1000L -const val SYSTEM_NOTICES_TAG = "m.server_notice" -const val DEFAULT_USER_PREFIX = "@notices:" const val MediaCaptionFieldKey = "caption" diff --git a/core/src/main/java/org/futo/circles/core/extensions/LiveDataExtensions.kt b/core/src/main/java/org/futo/circles/core/extensions/LiveDataExtensions.kt index a3cf3985514c67a214f46851d247682838f4ce6a..6ff976ec2d83ddf57ba3ecedbdd75b7657c670ac 100644 --- a/core/src/main/java/org/futo/circles/core/extensions/LiveDataExtensions.kt +++ b/core/src/main/java/org/futo/circles/core/extensions/LiveDataExtensions.kt @@ -3,6 +3,7 @@ package org.futo.circles.core.extensions import androidx.fragment.app.Fragment import androidx.lifecycle.LiveData import org.futo.circles.core.ErrorParser +import org.futo.circles.core.fragment.HasLoadingState fun <T> LiveData<Response<T>>.observeResponse( fragment: Fragment, @@ -13,7 +14,7 @@ fun <T> LiveData<Response<T>>.observeResponse( observe(fragment.viewLifecycleOwner) { it ?: return@observe onRequestInvoked?.invoke() - ?: run { (fragment as? org.futo.circles.core.fragment.HasLoadingState)?.stopLoading() } + ?: run { (fragment as? HasLoadingState)?.stopLoading() } when (it) { is Response.Success -> success(it.data) is Response.Error -> error?.invoke(it.message) diff --git a/core/src/main/java/org/futo/circles/core/extensions/MatrixRoomExtensions.kt b/core/src/main/java/org/futo/circles/core/extensions/MatrixRoomExtensions.kt deleted file mode 100644 index 32fe60b2b7539c43d9aa4f68a6858fde80b18aa5..0000000000000000000000000000000000000000 --- a/core/src/main/java/org/futo/circles/core/extensions/MatrixRoomExtensions.kt +++ /dev/null @@ -1,15 +0,0 @@ -package org.futo.circles.core.extensions - -import org.futo.circles.core.model.TIMELINE_TYPE -import org.futo.circles.core.provider.MatrixSessionProvider -import org.matrix.android.sdk.api.session.getRoom -import org.matrix.android.sdk.api.session.room.Room - -fun Room.getTimelineRoom(): Room? { - val session = MatrixSessionProvider.currentSession ?: return null - val childId = roomSummary()?.spaceChildren?.firstOrNull { - val room = session.getRoom(it.childRoomId)?.roomSummary() - room?.inviterId == null && room?.roomType == TIMELINE_TYPE - }?.childRoomId - return childId?.let { session.getRoom(it) } -} \ No newline at end of file diff --git a/core/src/main/java/org/futo/circles/core/extensions/MatrixSessionExtensions.kt b/core/src/main/java/org/futo/circles/core/extensions/MatrixSessionExtensions.kt index 1ca9f7ce0d9b4a39cd895847801e65e3d93f2ce1..c1f407d144dcee506ce9641b340eda376cd51371 100644 --- a/core/src/main/java/org/futo/circles/core/extensions/MatrixSessionExtensions.kt +++ b/core/src/main/java/org/futo/circles/core/extensions/MatrixSessionExtensions.kt @@ -6,7 +6,6 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.flow.mapLatest -import org.futo.circles.core.DEFAULT_USER_PREFIX import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.content.ContentUrlResolver import org.matrix.android.sdk.api.session.getUser @@ -43,20 +42,10 @@ fun Session.resolveUrl( fun Session.getUserIdsToExclude() = mutableListOf( myUserId, - DEFAULT_USER_PREFIX + getServerDomain() + "@notices:" + getServerDomain() ).toSet() fun Session.getServerDomain() = myUserId.substringAfter(":") -fun Session.getKnownUsersFlow() = - roomService().getRoomSummariesLive(roomSummaryQueryParams { excludeType = null }).asFlow() - .mapLatest { roomSummaries -> - val knowUsers = mutableSetOf<User>() - roomSummaries.forEach { summary -> - summary.otherMemberIds.forEach { knowUsers.add(getOrFetchUser(it)) } - } - knowUsers.toList().filterNot { getUserIdsToExclude().contains(it.userId) } - } - suspend fun Session.getOrFetchUser(userId: String): User = getUser(userId) ?: userService().resolveUser(userId) diff --git a/core/src/main/java/org/futo/circles/core/model/CirclesRoom.kt b/core/src/main/java/org/futo/circles/core/model/CirclesRoom.kt index 8e2d33b6dc91fa00468b3c7258a003fb8a6e9822..1b89b8a5ba157080955663615420525b12092f41 100644 --- a/core/src/main/java/org/futo/circles/core/model/CirclesRoom.kt +++ b/core/src/main/java/org/futo/circles/core/model/CirclesRoom.kt @@ -6,96 +6,119 @@ import org.matrix.android.sdk.api.session.room.model.RoomJoinRules import org.matrix.android.sdk.api.session.room.model.RoomType private const val orgPrefix = "org.futo" -private const val CIRCLES_SPACE_TAG = "$orgPrefix.space.circles" -const val SHARED_CIRCLES_SPACE_TAG = "$orgPrefix.space.circles.shared" -private const val GROUPS_SPACE_TAG = "$orgPrefix.space.groups" -const val PHOTOS_SPACE_TAG = "$orgPrefix.space.photos" -const val ROOT_SPACE_TAG = "$orgPrefix.space.root" -const val CIRCLE_TAG = "$orgPrefix.social.circle" const val GROUP_TYPE = "$orgPrefix.social.group" const val GALLERY_TYPE = "$orgPrefix.social.gallery" const val TIMELINE_TYPE = "$orgPrefix.social.timeline" +const val ROOT_SPACE_ACCOUNT_DATA_KEY = "root" +const val CIRCLES_SPACE_ACCOUNT_DATA_KEY = "circles" +const val PROFILE_SPACE_ACCOUNT_DATA_KEY = "profile" +const val PHOTOS_SPACE_ACCOUNT_DATA_KEY = "galleries" +const val PEOPLE_SPACE_ACCOUNT_DATA_KEY = "people" +const val GROUPS_SPACE_ACCOUNT_DATA_KEY = "groups" + sealed class CirclesRoom( @StringRes open val nameId: Int?, - open val tag: String?, - open val parentTag: String?, + open val parentAccountDataKey: String?, open val type: String?, - open val joinRules: RoomJoinRules? + open val joinRules: RoomJoinRules?, + open val accountDataKey: String? ) { fun isSpace(): Boolean = type == RoomType.SPACE + + open fun getTag(): String? = null } data class RootSpace( override val nameId: Int? = R.string.root_space_name, - override val tag: String? = ROOT_SPACE_TAG, - override val parentTag: String? = null, + override val parentAccountDataKey: String? = null, override val type: String? = RoomType.SPACE, - override val joinRules: RoomJoinRules? = null -) : CirclesRoom(nameId, tag, parentTag, type, joinRules) + override val joinRules: RoomJoinRules? = null, + override val accountDataKey: String? = ROOT_SPACE_ACCOUNT_DATA_KEY +) : CirclesRoom(nameId, parentAccountDataKey, type, joinRules, accountDataKey) { + override fun getTag(): String = "$orgPrefix.space.root" +} data class CirclesSpace( override val nameId: Int? = R.string.circles_space_name, - override val tag: String? = CIRCLES_SPACE_TAG, - override val parentTag: String? = ROOT_SPACE_TAG, + override val parentAccountDataKey: String? = ROOT_SPACE_ACCOUNT_DATA_KEY, override val type: String? = RoomType.SPACE, - override val joinRules: RoomJoinRules? = null -) : CirclesRoom(nameId, tag, parentTag, type, joinRules) + override val joinRules: RoomJoinRules? = null, + override val accountDataKey: String? = CIRCLES_SPACE_ACCOUNT_DATA_KEY +) : CirclesRoom(nameId, parentAccountDataKey, type, joinRules, accountDataKey) { + override fun getTag(): String = "$orgPrefix.space.circles" +} data class SharedCirclesSpace( override val nameId: Int? = R.string.shared_circles, - override val tag: String? = SHARED_CIRCLES_SPACE_TAG, - override val parentTag: String? = CIRCLES_SPACE_TAG, + override val parentAccountDataKey: String? = CIRCLES_SPACE_ACCOUNT_DATA_KEY, override val type: String? = RoomType.SPACE, - override val joinRules: RoomJoinRules? = RoomJoinRules.KNOCK -) : CirclesRoom(nameId, tag, parentTag, type, joinRules) + override val joinRules: RoomJoinRules? = RoomJoinRules.KNOCK, + override val accountDataKey: String? = PROFILE_SPACE_ACCOUNT_DATA_KEY +) : CirclesRoom(nameId, parentAccountDataKey, type, joinRules, accountDataKey) { + override fun getTag(): String = "$orgPrefix.space.circles.shared" +} data class PhotosSpace( override val nameId: Int? = R.string.photos_space_name, - override val tag: String? = PHOTOS_SPACE_TAG, - override val parentTag: String? = ROOT_SPACE_TAG, + override val parentAccountDataKey: String? = ROOT_SPACE_ACCOUNT_DATA_KEY, override val type: String? = RoomType.SPACE, - override val joinRules: RoomJoinRules? = null -) : CirclesRoom(nameId, tag, parentTag, type, joinRules) + override val joinRules: RoomJoinRules? = null, + override val accountDataKey: String? = PHOTOS_SPACE_ACCOUNT_DATA_KEY +) : CirclesRoom(nameId, parentAccountDataKey, type, joinRules, accountDataKey) { + override fun getTag(): String = "$orgPrefix.space.photos" +} + +data class PeopleSpace( + override val nameId: Int? = R.string.peopel_space_name, + override val parentAccountDataKey: String? = ROOT_SPACE_ACCOUNT_DATA_KEY, + override val type: String? = RoomType.SPACE, + override val joinRules: RoomJoinRules? = null, + override val accountDataKey: String? = PEOPLE_SPACE_ACCOUNT_DATA_KEY +) : CirclesRoom(nameId, parentAccountDataKey, type, joinRules, accountDataKey) { + + override fun getTag(): String = "$orgPrefix.space.people" +} data class GroupsSpace( override val nameId: Int? = R.string.groups_space_name, - override val tag: String? = GROUPS_SPACE_TAG, - override val parentTag: String? = ROOT_SPACE_TAG, + override val parentAccountDataKey: String? = ROOT_SPACE_ACCOUNT_DATA_KEY, override val type: String? = RoomType.SPACE, - override val joinRules: RoomJoinRules? = null -) : CirclesRoom(nameId, tag, parentTag, type, joinRules) + override val joinRules: RoomJoinRules? = null, + override val accountDataKey: String? = GROUPS_SPACE_ACCOUNT_DATA_KEY +) : CirclesRoom(nameId, parentAccountDataKey, type, joinRules, accountDataKey) { + + override fun getTag(): String = "$orgPrefix.space.groups" +} data class Circle( override val nameId: Int? = null, - override val tag: String? = CIRCLE_TAG, - override val parentTag: String? = CIRCLES_SPACE_TAG, + override val parentAccountDataKey: String? = CIRCLES_SPACE_ACCOUNT_DATA_KEY, override val type: String? = RoomType.SPACE, override val joinRules: RoomJoinRules? = null -) : CirclesRoom(nameId, tag, parentTag, type, joinRules) +) : CirclesRoom(nameId, parentAccountDataKey, type, joinRules, null) { + override fun getTag(): String = "$orgPrefix.social.circle" +} data class Group( override val nameId: Int? = null, - override val tag: String? = null, - override val parentTag: String? = GROUPS_SPACE_TAG, + override val parentAccountDataKey: String? = GROUPS_SPACE_ACCOUNT_DATA_KEY, override val type: String? = GROUP_TYPE, override val joinRules: RoomJoinRules? = RoomJoinRules.KNOCK -) : CirclesRoom(nameId, tag, parentTag, type, joinRules) +) : CirclesRoom(nameId, parentAccountDataKey, type, joinRules, null) data class Gallery( override val nameId: Int? = null, - override val tag: String? = null, - override val parentTag: String? = PHOTOS_SPACE_TAG, + override val parentAccountDataKey: String? = PHOTOS_SPACE_ACCOUNT_DATA_KEY, override val type: String? = GALLERY_TYPE, override val joinRules: RoomJoinRules? = RoomJoinRules.INVITE -) : CirclesRoom(nameId, tag, parentTag, type, joinRules) +) : CirclesRoom(nameId, parentAccountDataKey, type, joinRules, null) data class Timeline( override val nameId: Int? = null, - override val tag: String? = null, - override val parentTag: String? = null, + override val parentAccountDataKey: String? = null, override val type: String? = TIMELINE_TYPE, override val joinRules: RoomJoinRules? = RoomJoinRules.KNOCK -) : CirclesRoom(nameId, tag, parentTag, type, joinRules) \ No newline at end of file +) : CirclesRoom(nameId, parentAccountDataKey, type, joinRules, null) \ No newline at end of file diff --git a/core/src/main/java/org/futo/circles/core/model/LoadingData.kt b/core/src/main/java/org/futo/circles/core/model/LoadingData.kt index d49f5e49bd6b5f97c29ea74f7197af56f67c85e2..746fa0bcd3218d2d600aa436f907130fd157a38a 100644 --- a/core/src/main/java/org/futo/circles/core/model/LoadingData.kt +++ b/core/src/main/java/org/futo/circles/core/model/LoadingData.kt @@ -6,6 +6,6 @@ import org.futo.circles.core.R data class LoadingData( @StringRes var messageId: Int = R.string.loading, var progress: Int = 0, - var total: Int = 100, + var total: Int = 0, var isLoading: Boolean = true ) \ No newline at end of file diff --git a/core/src/main/java/org/futo/circles/core/model/SystemNoticeListItem.kt b/core/src/main/java/org/futo/circles/core/model/SystemNoticeListItem.kt deleted file mode 100644 index 934e1108720683510b8b8eb99749c8e05bd5e25c..0000000000000000000000000000000000000000 --- a/core/src/main/java/org/futo/circles/core/model/SystemNoticeListItem.kt +++ /dev/null @@ -1,9 +0,0 @@ -package org.futo.circles.core.model - -import org.futo.circles.core.list.IdEntity - -data class SystemNoticeListItem( - override val id: String, - val message: String, - val time: Long -) : IdEntity<String> \ No newline at end of file diff --git a/core/src/main/java/org/futo/circles/core/model/TaskStatus.kt b/core/src/main/java/org/futo/circles/core/model/TaskStatus.kt new file mode 100644 index 0000000000000000000000000000000000000000..368708d192b499075fa3ef4c38562e582cc552ef --- /dev/null +++ b/core/src/main/java/org/futo/circles/core/model/TaskStatus.kt @@ -0,0 +1,8 @@ +package org.futo.circles.core.model + +enum class TaskStatus { + IDLE, + RUNNING, + SUCCESS, + FAILED +} \ No newline at end of file diff --git a/core/src/main/java/org/futo/circles/core/notices/SystemNoticesCountSharedViewModel.kt b/core/src/main/java/org/futo/circles/core/notices/SystemNoticesCountSharedViewModel.kt deleted file mode 100644 index 62a4db05cc3e42ce6ed80264d30760a46a1cee2a..0000000000000000000000000000000000000000 --- a/core/src/main/java/org/futo/circles/core/notices/SystemNoticesCountSharedViewModel.kt +++ /dev/null @@ -1,41 +0,0 @@ -package org.futo.circles.core.notices - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.map -import dagger.hilt.android.lifecycle.HiltViewModel -import org.futo.circles.core.DEFAULT_USER_PREFIX -import org.futo.circles.core.SYSTEM_NOTICES_TAG -import org.futo.circles.core.extensions.launchBg -import org.futo.circles.core.provider.MatrixSessionProvider -import org.futo.circles.core.utils.UserUtils -import org.matrix.android.sdk.api.session.Session -import org.matrix.android.sdk.api.session.room.model.Membership -import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams -import javax.inject.Inject - -@HiltViewModel -class SystemNoticesCountSharedViewModel @Inject constructor() : ViewModel() { - - val systemNoticesCountLiveData = MatrixSessionProvider.currentSession?.roomService() - ?.getRoomSummariesLive(roomSummaryQueryParams()) - ?.map { list -> list.firstOrNull { it.hasTag(SYSTEM_NOTICES_TAG) }?.notificationCount } - - init { - autoAcceptNoticeRoomInvite() - } - - private fun autoAcceptNoticeRoomInvite() { - val session = MatrixSessionProvider.currentSession ?: return - session.roomService().getRoomSummaries(roomSummaryQueryParams { - memberships = listOf(Membership.INVITE) - }).firstOrNull { it.inviterId == getNoticesUserId(session) }?.let { - launchBg { session.roomService().joinRoom(it.roomId) } - } - } - - private fun getNoticesUserId(session: Session): String { - val domain = UserUtils.getServerDomain(session.myUserId) - return DEFAULT_USER_PREFIX + domain - } - -} \ No newline at end of file diff --git a/core/src/main/java/org/futo/circles/core/notices/SystemNoticesDialogFragment.kt b/core/src/main/java/org/futo/circles/core/notices/SystemNoticesDialogFragment.kt deleted file mode 100644 index 7f22b92c66e91c186b60c3103ef98c17bea058c7..0000000000000000000000000000000000000000 --- a/core/src/main/java/org/futo/circles/core/notices/SystemNoticesDialogFragment.kt +++ /dev/null @@ -1,41 +0,0 @@ -package org.futo.circles.core.notices - -import android.os.Bundle -import android.view.View -import androidx.fragment.app.viewModels -import dagger.hilt.android.AndroidEntryPoint -import org.futo.circles.core.databinding.DialogFragmentSystemNoticesBinding -import org.futo.circles.core.extensions.observeData -import org.futo.circles.core.fragment.BaseFullscreenDialogFragment -import org.futo.circles.core.notices.list.SystemNoticesTimelineAdapter - -@AndroidEntryPoint -class SystemNoticesDialogFragment : - BaseFullscreenDialogFragment(DialogFragmentSystemNoticesBinding::inflate) { - - private val viewModel by viewModels<SystemNoticesTimelineViewModel>() - - private val binding by lazy { - getBinding() as DialogFragmentSystemNoticesBinding - } - - private val listAdapter by lazy { - SystemNoticesTimelineAdapter { viewModel.loadMore() } - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - setupViews() - setupObservers() - } - - private fun setupViews() { - binding.rvTimeline.adapter = listAdapter - } - - private fun setupObservers() { - viewModel.systemNoticesTimelineEventsLiveData.observeData(this) { - listAdapter.submitList(it) - } - } -} \ No newline at end of file diff --git a/core/src/main/java/org/futo/circles/core/notices/SystemNoticesTimelineViewModel.kt b/core/src/main/java/org/futo/circles/core/notices/SystemNoticesTimelineViewModel.kt deleted file mode 100644 index feba6b2bade39ec350bbf8c2b5a3dadfa5b39e38..0000000000000000000000000000000000000000 --- a/core/src/main/java/org/futo/circles/core/notices/SystemNoticesTimelineViewModel.kt +++ /dev/null @@ -1,30 +0,0 @@ -package org.futo.circles.core.notices - -import androidx.lifecycle.map -import dagger.hilt.android.lifecycle.HiltViewModel -import org.futo.circles.core.model.PostContentType -import org.futo.circles.core.model.SystemNoticeListItem -import org.futo.circles.core.model.TextContent -import org.futo.circles.core.timeline.BaseTimelineViewModel -import org.futo.circles.core.timeline.data_source.SingleTimelineDataSource -import javax.inject.Inject - -@HiltViewModel -class SystemNoticesTimelineViewModel @Inject constructor( - timelineDataSource: SingleTimelineDataSource -) : BaseTimelineViewModel(timelineDataSource) { - - val systemNoticesTimelineEventsLiveData = - timelineDataSource.timelineEventsLiveData.map { list -> - list.mapNotNull { - if (it.content.type == PostContentType.TEXT_CONTENT) - SystemNoticeListItem( - it.id, - (it.content as? TextContent)?.message ?: "", - it.postInfo.timestamp - ) - else null - } - } - -} \ No newline at end of file diff --git a/core/src/main/java/org/futo/circles/core/notices/list/SystemNoticesTimelineAdapter.kt b/core/src/main/java/org/futo/circles/core/notices/list/SystemNoticesTimelineAdapter.kt deleted file mode 100644 index 3dee08158d45ecba70324aa96c3109bfea83fac0..0000000000000000000000000000000000000000 --- a/core/src/main/java/org/futo/circles/core/notices/list/SystemNoticesTimelineAdapter.kt +++ /dev/null @@ -1,27 +0,0 @@ -package org.futo.circles.core.notices.list - - -import android.view.ViewGroup -import org.futo.circles.core.list.BaseRvAdapter -import org.futo.circles.core.model.SystemNoticeListItem - -class SystemNoticesTimelineAdapter( - private val onLoadMore: () -> Unit -) : BaseRvAdapter<SystemNoticeListItem, SystemNoticesViewHolder>(DefaultIdEntityCallback()) { - - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SystemNoticesViewHolder { - return SystemNoticesViewHolder(parent) - } - - override fun onBindViewHolder(holder: SystemNoticesViewHolder, position: Int) { - holder.bind(getItem(position)) - if (position >= itemCount - LOAD_MORE_THRESHOLD) onLoadMore() - } - - - companion object { - private const val LOAD_MORE_THRESHOLD = 10 - } - -} \ No newline at end of file diff --git a/core/src/main/java/org/futo/circles/core/notices/list/SystemNoticesViewHolder.kt b/core/src/main/java/org/futo/circles/core/notices/list/SystemNoticesViewHolder.kt deleted file mode 100644 index fba7f8b77666e085b8b4a83a847e288d4edccd1b..0000000000000000000000000000000000000000 --- a/core/src/main/java/org/futo/circles/core/notices/list/SystemNoticesViewHolder.kt +++ /dev/null @@ -1,25 +0,0 @@ -package org.futo.circles.core.notices.list - -import android.view.ViewGroup -import androidx.recyclerview.widget.RecyclerView -import org.futo.circles.core.databinding.ListItemSystemNoticesBinding -import org.futo.circles.core.list.ViewBindingHolder -import org.futo.circles.core.model.SystemNoticeListItem -import java.text.DateFormat -import java.util.Date - -class SystemNoticesViewHolder( - parent: ViewGroup -) : RecyclerView.ViewHolder(inflate(parent, ListItemSystemNoticesBinding::inflate)) { - - private companion object : ViewBindingHolder - - private val binding = baseBinding as ListItemSystemNoticesBinding - - fun bind(data: SystemNoticeListItem) { - with(binding) { - tvMessage.text = data.message - tvTime.text = DateFormat.getDateTimeInstance().format(Date(data.time)) - } - } -} \ No newline at end of file diff --git a/core/src/main/java/org/futo/circles/core/room/CoreSpacesTreeBuilder.kt b/core/src/main/java/org/futo/circles/core/room/CoreSpacesTreeBuilder.kt deleted file mode 100644 index 6e81911abed55396681c82ac6eda75d63e4ffce0..0000000000000000000000000000000000000000 --- a/core/src/main/java/org/futo/circles/core/room/CoreSpacesTreeBuilder.kt +++ /dev/null @@ -1,53 +0,0 @@ -package org.futo.circles.core.room - -import android.content.Context -import androidx.lifecycle.MutableLiveData -import dagger.hilt.android.qualifiers.ApplicationContext -import kotlinx.coroutines.delay -import org.futo.circles.core.CREATE_ROOM_DELAY -import org.futo.circles.core.R -import org.futo.circles.core.model.CirclesSpace -import org.futo.circles.core.model.Gallery -import org.futo.circles.core.model.GroupsSpace -import org.futo.circles.core.model.LoadingData -import org.futo.circles.core.model.PhotosSpace -import org.futo.circles.core.model.ROOT_SPACE_TAG -import org.futo.circles.core.model.RootSpace -import org.futo.circles.core.model.SharedCirclesSpace -import org.futo.circles.core.provider.MatrixSessionProvider -import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams -import javax.inject.Inject - -class CoreSpacesTreeBuilder @Inject constructor( - @ApplicationContext private val context: Context, - private val createRoomDataSource: CreateRoomDataSource -) { - - val loadingLiveData = MutableLiveData<LoadingData>() - - private val coreSpaces = listOf( - RootSpace(), CirclesSpace(), GroupsSpace(), PhotosSpace() - ) - - suspend fun createCoreSpacesTree() { - loadingLiveData.postValue( - LoadingData( - total = 0, - messageId = R.string.configuring_workspace, - isLoading = true - ) - ) - coreSpaces.forEach { - createRoomDataSource.createRoom(it) - delay(CREATE_ROOM_DELAY) - } - createRoomDataSource.createRoom(SharedCirclesSpace()) - delay(CREATE_ROOM_DELAY) - createRoomDataSource.createRoom(Gallery(), context.getString(R.string.photos)) - loadingLiveData.postValue(LoadingData(isLoading = false)) - } - - fun isCirclesHierarchyCreated(): Boolean = MatrixSessionProvider.currentSession?.roomService() - ?.getRoomSummaries(roomSummaryQueryParams { excludeType = null }) - ?.firstOrNull { summary -> summary.hasTag(ROOT_SPACE_TAG) } != null -} \ No newline at end of file diff --git a/core/src/main/java/org/futo/circles/core/room/CreateRoomDataSource.kt b/core/src/main/java/org/futo/circles/core/room/CreateRoomDataSource.kt index 3a493229e1d813948affc80265937dd8388444af..59d0d28adf9c0350517e01f3066d0ff1742331b1 100644 --- a/core/src/main/java/org/futo/circles/core/room/CreateRoomDataSource.kt +++ b/core/src/main/java/org/futo/circles/core/room/CreateRoomDataSource.kt @@ -7,7 +7,8 @@ import org.futo.circles.core.model.Circle import org.futo.circles.core.model.CirclesRoom import org.futo.circles.core.model.Timeline import org.futo.circles.core.provider.MatrixSessionProvider -import org.futo.circles.core.utils.getSharedCirclesSpaceId +import org.futo.circles.core.workspace.SharedCircleDataSource +import org.futo.circles.core.workspace.SpacesTreeAccountDataSource import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toContent import org.matrix.android.sdk.api.session.getRoom @@ -25,21 +26,33 @@ import javax.inject.Inject class CreateRoomDataSource @Inject constructor( @ApplicationContext private val context: Context, - private val roomRelationsBuilder: RoomRelationsBuilder + private val roomRelationsBuilder: RoomRelationsBuilder, + private val spacesTreeAccountDataSource: SpacesTreeAccountDataSource, + private val sharedCircleDataSource: SharedCircleDataSource ) { - private val session by lazy { MatrixSessionProvider.currentSession } + private val session by lazy { MatrixSessionProvider.getSessionOrThrow() } - suspend fun createCircleWithTimeline( + suspend fun createRoom( + circlesRoom: CirclesRoom, name: String? = null, + topic: String? = null, iconUri: Uri? = null, inviteIds: List<String>? = null, - isPublicCircle: Boolean + isPublicCircle: Boolean = false ): String { - val circleId = createRoom(Circle(), name, null, iconUri) - val timelineId = createCircleTimeline(circleId, name, iconUri, inviteIds) - if (isPublicCircle) addToSharedCircles(timelineId) - return circleId + val id = session.roomService().createRoom( + getParams(circlesRoom, name, topic, iconUri, inviteIds) + ) + circlesRoom.parentAccountDataKey?.let { key -> + val parentId = spacesTreeAccountDataSource.getRoomIdByKey(key) + parentId?.let { roomRelationsBuilder.setRelations(id, it) } + } + if (circlesRoom is Circle) { + val timelineId = createCircleTimeline(id, name, iconUri, inviteIds) + if (isPublicCircle) sharedCircleDataSource.addToSharedCircles(timelineId) + } + return id } suspend fun createCircleTimeline( @@ -48,29 +61,10 @@ class CreateRoomDataSource @Inject constructor( inviteIds: List<String>? = null ): String { val timelineId = createRoom(Timeline(), name, null, iconUri, inviteIds) - session?.getRoom(circleId) - ?.let { circle -> roomRelationsBuilder.setRelations(timelineId, circle) } + roomRelationsBuilder.setRelations(timelineId, circleId) return timelineId } - suspend fun createRoom( - circlesRoom: CirclesRoom, - name: String? = null, - topic: String? = null, - iconUri: Uri? = null, - inviteIds: List<String>? = null - ): String { - val id = session?.roomService()?.createRoom( - getParams(circlesRoom, name, topic, iconUri, inviteIds) - ) ?: throw Exception("Can not create room") - circlesRoom.tag?.let { session?.getRoom(id)?.tagsService()?.addTag(it, null) } - circlesRoom.parentTag?.let { tag -> - roomRelationsBuilder.findRoomByTag(tag) - ?.let { room -> roomRelationsBuilder.setRelations(id, room) } - } - return id - } - private fun getParams( circlesRoom: CirclesRoom, name: String? = null, @@ -112,18 +106,4 @@ class CreateRoomDataSource @Inject constructor( ) ) } - - suspend fun addToSharedCircles(timelineId: String) { - session?.getRoom(getSharedCirclesSpaceId() ?: "") - ?.let { sharedCirclesSpace -> - roomRelationsBuilder.setRelations(timelineId, sharedCirclesSpace) - } - } - - suspend fun removeFromSharedCircles(timelineId: String) { - session?.getRoom(getSharedCirclesSpaceId() ?: "") - ?.let { sharedCirclesSpace -> - roomRelationsBuilder.removeRelations(timelineId, sharedCirclesSpace.roomId) - } - } } diff --git a/core/src/main/java/org/futo/circles/core/room/RoomRelationsBuilder.kt b/core/src/main/java/org/futo/circles/core/room/RoomRelationsBuilder.kt index 67d31d3c28b8c1cfe348de50c84abda439df7349..4866369a1065b684ea4457836623a6c79475bf4e 100644 --- a/core/src/main/java/org/futo/circles/core/room/RoomRelationsBuilder.kt +++ b/core/src/main/java/org/futo/circles/core/room/RoomRelationsBuilder.kt @@ -2,24 +2,25 @@ package org.futo.circles.core.room import org.futo.circles.core.extensions.getRoomOwners import org.futo.circles.core.model.CirclesRoom -import org.futo.circles.core.model.Gallery -import org.futo.circles.core.model.Group import org.futo.circles.core.provider.MatrixSessionProvider +import org.futo.circles.core.utils.getJoinedRoomById +import org.futo.circles.core.workspace.SpacesTreeAccountDataSource +import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.session.getRoom -import org.matrix.android.sdk.api.session.room.Room -import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams import javax.inject.Inject -class RoomRelationsBuilder @Inject constructor() { +class RoomRelationsBuilder @Inject constructor( + private val spacesTreeAccountDataSource: SpacesTreeAccountDataSource +) { private val session by lazy { MatrixSessionProvider.currentSession } - suspend fun setRelations(childId: String, parentRoom: Room, isRoomCreatedByMe: Boolean = true) { + suspend fun setRelations(childId: String, parentRoomId: String) { val via = listOf(getHomeServerDomain()) - if (isRoomCreatedByMe) { - session?.spaceService()?.setSpaceParent(childId, parentRoom.roomId, true, via) + tryOrNull { + session?.spaceService()?.setSpaceParent(childId, parentRoomId, false, via) } - parentRoom.asSpace()?.addChildren(childId, via, null) + getJoinedRoomById(parentRoomId)?.asSpace()?.addChildren(childId, via, null) } suspend fun removeRelations(childId: String, parentId: String) { @@ -35,32 +36,14 @@ class RoomRelationsBuilder @Inject constructor() { } } - suspend fun setInvitedGroupRelations(roomId: String) = - setInvitedRoomRelations(roomId, Group()) - - suspend fun setInvitedGalleryRelations(roomId: String) = - setInvitedRoomRelations(roomId, Gallery()) - - private suspend fun setInvitedRoomRelations(roomId: String, circlesRoom: CirclesRoom) { - circlesRoom.tag?.let { session?.getRoom(roomId)?.tagsService()?.addTag(it, null) } - circlesRoom.parentTag?.let { tag -> - findRoomByTag(tag) - ?.let { room -> setRelations(roomId, room, false) } - } - } - - suspend fun setInvitedCircleRelations(roomId: String, parentCircleId: String) { - session?.getRoom(parentCircleId)?.let { parentCircle -> - setRelations(roomId, parentCircle, false) - } + suspend fun setInvitedRoomRelations(roomId: String, circlesRoom: CirclesRoom) { + val key = circlesRoom.parentAccountDataKey ?: return + val parentId = spacesTreeAccountDataSource.getRoomIdByKey(key) ?: return + setRelations(roomId, parentId) } - fun findRoomByTag(tag: String): Room? { - val roomWithTagId = - session?.roomService()?.getRoomSummaries(roomSummaryQueryParams { excludeType = null }) - ?.firstOrNull { summary -> summary.tags.firstOrNull { it.name == tag } != null } - ?.roomId - return roomWithTagId?.let { session?.getRoom(it) } + suspend fun setInvitedRoomRelations(roomId: String, parentCircleId: String) { + setRelations(roomId, parentCircleId) } private fun getHomeServerDomain() = session?.sessionParams?.homeServerHost ?: "" diff --git a/core/src/main/java/org/futo/circles/core/room/circles/following/FollowingDataSource.kt b/core/src/main/java/org/futo/circles/core/room/circles/following/FollowingDataSource.kt index 3f09ea9b8c188b302467b05975997d7a944c5883..d0c2b6d830ccc34fca7d87b5ebb83d8fc30de543 100644 --- a/core/src/main/java/org/futo/circles/core/room/circles/following/FollowingDataSource.kt +++ b/core/src/main/java/org/futo/circles/core/room/circles/following/FollowingDataSource.kt @@ -5,13 +5,11 @@ import androidx.lifecycle.map import dagger.hilt.android.scopes.ViewModelScoped import org.futo.circles.core.extensions.createResult import org.futo.circles.core.extensions.getOrThrow -import org.futo.circles.core.model.CIRCLE_TAG import org.futo.circles.core.model.toFollowingListItem import org.futo.circles.core.provider.MatrixSessionProvider import org.futo.circles.core.room.RoomRelationsBuilder +import org.futo.circles.core.utils.getJoinedRoomById import org.matrix.android.sdk.api.session.getRoom -import org.matrix.android.sdk.api.session.room.model.Membership -import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams import javax.inject.Inject @ViewModelScoped @@ -42,16 +40,7 @@ class FollowingDataSource @Inject constructor( session.roomService().leaveRoom(childRoomId) } - private fun getFollowingInCircleCount(roomId: String): Int { - var followingCount = 0 - session.roomService().getRoomSummaries(roomSummaryQueryParams { excludeType = null }) - .filter { summary -> - summary.hasTag(CIRCLE_TAG) && summary.membership == Membership.JOIN - }.forEach { circle -> - circle.spaceChildren?.firstOrNull { it.childRoomId == roomId }?.let { - followingCount++ - } - } - return followingCount - } + private fun getFollowingInCircleCount(roomId: String): Int = + getJoinedRoomById(roomId)?.roomSummary()?.spaceParents?.size ?: 0 + } \ No newline at end of file diff --git a/core/src/main/java/org/futo/circles/core/room/create/CreateRoomViewModel.kt b/core/src/main/java/org/futo/circles/core/room/create/CreateRoomViewModel.kt index e0bba3d1d330b29704728987c25b9d1711e31f29..27e8457a5650128bc48d3c9affd64f722a950356 100644 --- a/core/src/main/java/org/futo/circles/core/room/create/CreateRoomViewModel.kt +++ b/core/src/main/java/org/futo/circles/core/room/create/CreateRoomViewModel.kt @@ -8,6 +8,7 @@ import org.futo.circles.core.SingleEventLiveData import org.futo.circles.core.extensions.Response import org.futo.circles.core.extensions.createResult import org.futo.circles.core.extensions.launchBg +import org.futo.circles.core.model.Circle import org.futo.circles.core.model.CircleRoomTypeArg import org.futo.circles.core.model.Gallery import org.futo.circles.core.model.Group @@ -58,13 +59,13 @@ class CreateRoomViewModel @Inject constructor( name: String, inviteIds: List<String>?, isPublicCircle: Boolean - ) = - dataSource.createCircleWithTimeline( - name = name, - iconUri = selectedImageLiveData.value, - inviteIds = inviteIds, - isPublicCircle - ) + ) = dataSource.createRoom( + circlesRoom = Circle(), + name = name, + iconUri = selectedImageLiveData.value, + inviteIds = inviteIds, + isPublicCircle = isPublicCircle + ) private suspend fun createGallery(name: String) = dataSource.createRoom( circlesRoom = Gallery(), diff --git a/core/src/main/java/org/futo/circles/core/room/invite/InviteRequestsDataSource.kt b/core/src/main/java/org/futo/circles/core/room/invite/InviteRequestsDataSource.kt index decf97715279a737f3b9d1386afdaada34a85b3b..9baceb0d23e7e689f4fe13e537d48051fe372134 100644 --- a/core/src/main/java/org/futo/circles/core/room/invite/InviteRequestsDataSource.kt +++ b/core/src/main/java/org/futo/circles/core/room/invite/InviteRequestsDataSource.kt @@ -6,6 +6,8 @@ import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll import org.futo.circles.core.extensions.createResult import org.futo.circles.core.model.CircleRoomTypeArg +import org.futo.circles.core.model.Gallery +import org.futo.circles.core.model.Group import org.futo.circles.core.provider.MatrixSessionProvider import org.futo.circles.core.room.RoomRelationsBuilder import org.matrix.android.sdk.api.session.getRoom @@ -27,11 +29,10 @@ class InviteRequestsDataSource @Inject constructor( suspend fun acceptInvite(roomId: String, roomType: CircleRoomTypeArg) = createResult { MatrixSessionProvider.currentSession?.roomService()?.joinRoom(roomId) when (roomType) { - CircleRoomTypeArg.Group -> roomRelationsBuilder.setInvitedGroupRelations(roomId) - CircleRoomTypeArg.Photo -> roomRelationsBuilder.setInvitedGroupRelations(roomId) + CircleRoomTypeArg.Group -> roomRelationsBuilder.setInvitedRoomRelations(roomId, Group()) + CircleRoomTypeArg.Photo -> roomRelationsBuilder.setInvitedRoomRelations(roomId, Gallery()) CircleRoomTypeArg.Circle -> throw IllegalArgumentException("Circle has different relations") } - } suspend fun rejectInvite(roomId: String) = createResult { diff --git a/core/src/main/java/org/futo/circles/core/room/update/UpdateRoomDataSource.kt b/core/src/main/java/org/futo/circles/core/room/update/UpdateRoomDataSource.kt index 898a25fa6e0d749523504c0860a0487ca8e71208..1df0a20589f0705fbe99e52e530c0f461acc99b1 100644 --- a/core/src/main/java/org/futo/circles/core/room/update/UpdateRoomDataSource.kt +++ b/core/src/main/java/org/futo/circles/core/room/update/UpdateRoomDataSource.kt @@ -9,9 +9,8 @@ import org.futo.circles.core.extensions.createResult import org.futo.circles.core.extensions.getFilename import org.futo.circles.core.extensions.getOrThrow import org.futo.circles.core.provider.MatrixSessionProvider -import org.futo.circles.core.room.CreateRoomDataSource import org.futo.circles.core.utils.getTimelineRoomFor -import org.futo.circles.core.utils.isCircleShared +import org.futo.circles.core.workspace.SharedCircleDataSource import org.matrix.android.sdk.api.session.getRoom import java.util.UUID import javax.inject.Inject @@ -20,7 +19,7 @@ import javax.inject.Inject class UpdateRoomDataSource @Inject constructor( savedStateHandle: SavedStateHandle, @ApplicationContext private val context: Context, - private val createRoomDataSource: CreateRoomDataSource + private val sharedCircleDataSource: SharedCircleDataSource ) { private val roomId: String = savedStateHandle.getOrThrow("roomId") @@ -42,8 +41,8 @@ class UpdateRoomDataSource @Inject constructor( private suspend fun handelPrivateSharedVisibilityUpdate(isPublic: Boolean) { val timelineId = room?.roomId?.let { getTimelineRoomFor(it)?.roomId } ?: return - if (isPublic) createRoomDataSource.addToSharedCircles(timelineId) - else createRoomDataSource.removeFromSharedCircles(timelineId) + if (isPublic) sharedCircleDataSource.addToSharedCircles(timelineId) + else sharedCircleDataSource.removeFromSharedCircles(timelineId) } fun isNameChanged(newName: String) = room?.roomSummary()?.displayName != newName @@ -51,7 +50,9 @@ class UpdateRoomDataSource @Inject constructor( fun isTopicChanged(newTopic: String) = room?.roomSummary()?.topic != newTopic fun isPrivateSharedChanged(isPublic: Boolean) = room?.roomId?.let { - isCircleShared(it) != isPublic + sharedCircleDataSource.isCircleShared(it) != isPublic } ?: false + fun isCircleShared(circleId: String) = sharedCircleDataSource.isCircleShared(circleId) + } \ No newline at end of file diff --git a/core/src/main/java/org/futo/circles/core/room/update/UpdateRoomDialogFragment.kt b/core/src/main/java/org/futo/circles/core/room/update/UpdateRoomDialogFragment.kt index bb30e7cd7b4ef88ad5bf7408e326bab1c504c367..3bbaeb8d621640c999fe35cd77aae8384bbbda7d 100644 --- a/core/src/main/java/org/futo/circles/core/room/update/UpdateRoomDialogFragment.kt +++ b/core/src/main/java/org/futo/circles/core/room/update/UpdateRoomDialogFragment.kt @@ -21,12 +21,12 @@ abstract class UpdateRoomDialogFragment(inflate: (LayoutInflater, ViewGroup?, Bo abstract val roomId: String - private val viewModel by viewModels<UpdateRoomViewModel>() + protected val viewModel by viewModels<UpdateRoomViewModel>() abstract val mediaPickerHelper: MediaPickerHelper abstract val successMessageResId: Int abstract fun onCoverImageSelected(uri: Uri) - abstract fun setInitialGroupData(room: RoomSummary) + abstract fun setInitialRoomData(room: RoomSummary) abstract fun setUpdateButtonEnabled(isEnabled: Boolean) protected fun changeCoverImage() { @@ -67,7 +67,7 @@ abstract class UpdateRoomDialogFragment(inflate: (LayoutInflater, ViewGroup?, Bo } ) viewModel.groupSummaryLiveData.observeData(this) { - it?.let { setInitialGroupData(it) } + it?.let { setInitialRoomData(it) } } viewModel.isRoomDataChangedLiveData.observeData(this) { setUpdateButtonEnabled(it) diff --git a/core/src/main/java/org/futo/circles/core/room/update/UpdateRoomViewModel.kt b/core/src/main/java/org/futo/circles/core/room/update/UpdateRoomViewModel.kt index bf320d7de71d57ad20ca2803ecb41ff2205f8057..2ff350d77a8645bb21cd7d0ec83d9d1b5848e0f3 100644 --- a/core/src/main/java/org/futo/circles/core/room/update/UpdateRoomViewModel.kt +++ b/core/src/main/java/org/futo/circles/core/room/update/UpdateRoomViewModel.kt @@ -39,4 +39,5 @@ class UpdateRoomViewModel @Inject constructor( isRoomDataChangedLiveData.postValue(isDataUpdated) } + fun isCircleShared(circleId: String) = dataSource.isCircleShared(circleId) } \ No newline at end of file diff --git a/core/src/main/java/org/futo/circles/core/room/update/circle/UpdateCircleDialogFragment.kt b/core/src/main/java/org/futo/circles/core/room/update/circle/UpdateCircleDialogFragment.kt index f08ba933573ac9e0bd0486af4970d91248ab3483..8f6756fd1c048ea3e857eee8f303bb849dfe2dba 100644 --- a/core/src/main/java/org/futo/circles/core/room/update/circle/UpdateCircleDialogFragment.kt +++ b/core/src/main/java/org/futo/circles/core/room/update/circle/UpdateCircleDialogFragment.kt @@ -13,7 +13,6 @@ import org.futo.circles.core.extensions.getText import org.futo.circles.core.extensions.loadProfileIcon import org.futo.circles.core.picker.helper.MediaPickerHelper import org.futo.circles.core.room.update.UpdateRoomDialogFragment -import org.futo.circles.core.utils.isCircleShared import org.matrix.android.sdk.api.session.room.model.RoomSummary @AndroidEntryPoint @@ -40,10 +39,10 @@ class UpdateCircleDialogFragment : onInputDataChanged() } - override fun setInitialGroupData(room: RoomSummary) { + override fun setInitialRoomData(room: RoomSummary) { binding.ivCover.loadProfileIcon(room.avatarUrl, room.displayName) binding.tilName.editText?.setText(room.displayName) - val isCircleShared = isCircleShared(roomId) + val isCircleShared = viewModel.isCircleShared(roomId) binding.btnPrivate.isChecked = !isCircleShared binding.btnPublic.isChecked = isCircleShared } diff --git a/core/src/main/java/org/futo/circles/core/room/update/gallery/UpdateGalleryDialogFragment.kt b/core/src/main/java/org/futo/circles/core/room/update/gallery/UpdateGalleryDialogFragment.kt index 74f58ceabcdc6588fdee323969ea8ae2248978f0..c90e191be48dbab0949b822f68926c7f284923e2 100644 --- a/core/src/main/java/org/futo/circles/core/room/update/gallery/UpdateGalleryDialogFragment.kt +++ b/core/src/main/java/org/futo/circles/core/room/update/gallery/UpdateGalleryDialogFragment.kt @@ -40,7 +40,7 @@ class UpdateGalleryDialogFragment : onInputDataChanged() } - override fun setInitialGroupData(room: RoomSummary) { + override fun setInitialRoomData(room: RoomSummary) { binding.ivCover.loadProfileIcon(room.avatarUrl, room.displayName) binding.tilName.editText?.setText(room.displayName) } diff --git a/core/src/main/java/org/futo/circles/core/room/update/group/UpdateGroupDialogFragment.kt b/core/src/main/java/org/futo/circles/core/room/update/group/UpdateGroupDialogFragment.kt index f4d8a04cf4f33f6adde14c180796951bcf1df244..380cb01d0c4275d6f3bf0be120ec11c6ef2730b3 100644 --- a/core/src/main/java/org/futo/circles/core/room/update/group/UpdateGroupDialogFragment.kt +++ b/core/src/main/java/org/futo/circles/core/room/update/group/UpdateGroupDialogFragment.kt @@ -39,7 +39,7 @@ class UpdateGroupDialogFragment : onInputDataChanged() } - override fun setInitialGroupData(room: RoomSummary) { + override fun setInitialRoomData(room: RoomSummary) { binding.ivCover.loadProfileIcon(room.avatarUrl, room.displayName) binding.tilName.editText?.setText(room.displayName) binding.tilTopic.editText?.setText(room.topic) diff --git a/core/src/main/java/org/futo/circles/core/select_users/SearchUserDataSource.kt b/core/src/main/java/org/futo/circles/core/select_users/SearchUserDataSource.kt index 07c77fb7ab2c1192260f1a2865465285a026ed89..ccb777f32fef15e38a62ba3d1ee9c90416d50491 100644 --- a/core/src/main/java/org/futo/circles/core/select_users/SearchUserDataSource.kt +++ b/core/src/main/java/org/futo/circles/core/select_users/SearchUserDataSource.kt @@ -1,15 +1,19 @@ package org.futo.circles.core.select_users +import androidx.lifecycle.asFlow import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.mapLatest import org.futo.circles.core.extensions.Response import org.futo.circles.core.extensions.createResult -import org.futo.circles.core.extensions.getKnownUsersFlow +import org.futo.circles.core.extensions.getOrFetchUser import org.futo.circles.core.extensions.getServerDomain +import org.futo.circles.core.extensions.getUserIdsToExclude import org.futo.circles.core.provider.MatrixSessionProvider +import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams import org.matrix.android.sdk.api.session.user.model.User @@ -36,6 +40,16 @@ class SearchUserDataSource @Inject constructor() { } } ?: flowOf() + private fun Session.getKnownUsersFlow() = + roomService().getRoomSummariesLive(roomSummaryQueryParams { excludeType = null }).asFlow() + .mapLatest { roomSummaries -> + val knowUsers = mutableSetOf<User>() + roomSummaries.forEach { summary -> + summary.otherMemberIds.forEach { knowUsers.add(getOrFetchUser(it)) } + } + knowUsers.toList().filterNot { getUserIdsToExclude().contains(it.userId) } + } + suspend fun searchSuggestions( query: String, userIdsToExclude: Set<String> = emptySet() diff --git a/core/src/main/java/org/futo/circles/core/select_users/SelectUsersDataSource.kt b/core/src/main/java/org/futo/circles/core/select_users/SelectUsersDataSource.kt index 7b604713af9e614c177a4945dfe0a13f9f535beb..0b2eea4690fc54f5202d1bd280fd17ca29cfa68f 100644 --- a/core/src/main/java/org/futo/circles/core/select_users/SelectUsersDataSource.kt +++ b/core/src/main/java/org/futo/circles/core/select_users/SelectUsersDataSource.kt @@ -1,12 +1,15 @@ package org.futo.circles.core.select_users import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.asFlow import dagger.hilt.android.scopes.ViewModelScoped import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.mapLatest +import org.futo.circles.core.extensions.getOrFetchUser import org.futo.circles.core.extensions.getUserIdsToExclude import org.futo.circles.core.mapping.toUserListItem import org.futo.circles.core.model.CirclesUserSummary @@ -17,9 +20,11 @@ import org.futo.circles.core.model.UserListItem import org.futo.circles.core.provider.MatrixSessionProvider import org.futo.circles.core.utils.UserUtils import org.matrix.android.sdk.api.MatrixPatterns +import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams import org.matrix.android.sdk.api.session.room.model.Membership +import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams import org.matrix.android.sdk.api.session.user.model.User import javax.inject.Inject diff --git a/core/src/main/java/org/futo/circles/core/utils/RoomUtils.kt b/core/src/main/java/org/futo/circles/core/utils/RoomUtils.kt index 6d61643c419f295c3dd52be6a775042cbcef0afd..ca975587a66db13ae8dd52a567b3824c656df24c 100644 --- a/core/src/main/java/org/futo/circles/core/utils/RoomUtils.kt +++ b/core/src/main/java/org/futo/circles/core/utils/RoomUtils.kt @@ -1,17 +1,19 @@ package org.futo.circles.core.utils -import org.futo.circles.core.SYSTEM_NOTICES_TAG -import org.futo.circles.core.extensions.getRoomOwners -import org.futo.circles.core.extensions.getTimelineRoom -import org.futo.circles.core.model.PHOTOS_SPACE_TAG -import org.futo.circles.core.model.SHARED_CIRCLES_SPACE_TAG +import org.futo.circles.core.model.TIMELINE_TYPE import org.futo.circles.core.provider.MatrixSessionProvider import org.matrix.android.sdk.api.session.getRoom -import org.matrix.android.sdk.api.session.getRoomSummary import org.matrix.android.sdk.api.session.room.Room import org.matrix.android.sdk.api.session.room.model.Membership -import org.matrix.android.sdk.api.session.room.model.RoomType -import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams + +fun Room.getTimelineRoom(): Room? { + val session = MatrixSessionProvider.currentSession ?: return null + val childId = roomSummary()?.spaceChildren?.firstOrNull { + val room = session.getRoom(it.childRoomId)?.roomSummary() + room?.inviterId == null && room?.roomType == TIMELINE_TYPE + }?.childRoomId + return childId?.let { session.getRoom(it) } +} fun getTimelineRoomFor(circleId: String): Room? { val session = MatrixSessionProvider.currentSession ?: return null @@ -21,33 +23,9 @@ fun getTimelineRoomFor(circleId: String): Room? { fun getTimelineRoomIdOrThrow(circleId: String) = getTimelineRoomFor(circleId)?.roomId ?: throw IllegalArgumentException("Timeline not found") -fun getSystemNoticesRoomId(): String? = getJoinedRoomIdByTag(SYSTEM_NOTICES_TAG) - -fun getJoinedRoomIdByTag(tag: String): String? { - val session = MatrixSessionProvider.currentSession ?: return null - return session.roomService().getRoomSummaries(roomSummaryQueryParams()) - .firstOrNull { it.membership == Membership.JOIN && it.hasTag(tag) }?.roomId -} - -fun getPhotosSpaceId(): String? = getSpaceIdByTag(PHOTOS_SPACE_TAG) -fun getSharedCirclesSpaceId(): String? = getSpaceIdByTag(SHARED_CIRCLES_SPACE_TAG) - -fun getSharedCircleFor(userId: String) = MatrixSessionProvider.currentSession?.roomService() - ?.getRoomSummaries(roomSummaryQueryParams { excludeType = null })?.firstOrNull { summary -> - summary.roomType == RoomType.SPACE && summary.membership == Membership.JOIN && - getRoomOwners(summary.roomId).map { it.userId }.contains(userId) - } -fun getSpaceIdByTag(tag: String): String? { +fun getJoinedRoomById(roomId: String): Room? { val session = MatrixSessionProvider.currentSession ?: return null - return session.roomService().getRoomSummaries(roomSummaryQueryParams { excludeType = null }) - .firstOrNull { it.hasTag(tag) && it.roomType == RoomType.SPACE }?.roomId -} - -fun isCircleShared(circleId: String): Boolean { - val timelineId = getTimelineRoomFor(circleId)?.roomId - val sharedCirclesTimelinesIds = getSharedCirclesSpaceId()?.let { - MatrixSessionProvider.currentSession?.getRoomSummary(it)?.spaceChildren?.map { it.childRoomId } - } ?: emptyList() - return sharedCirclesTimelinesIds.contains(timelineId) + return session.roomService().getRoom(roomId) + ?.takeIf { it.roomSummary()?.membership == Membership.JOIN } } \ No newline at end of file diff --git a/core/src/main/java/org/futo/circles/core/view/LoadingDialog.kt b/core/src/main/java/org/futo/circles/core/view/LoadingDialog.kt index e8a24bfe12ab9885d59258990fd82e9543d416ee..e4e5b6d81eaf85544f5a35a0124290829c25f691 100644 --- a/core/src/main/java/org/futo/circles/core/view/LoadingDialog.kt +++ b/core/src/main/java/org/futo/circles/core/view/LoadingDialog.kt @@ -25,7 +25,6 @@ class LoadingDialog(context: Context) : AppCompatDialog(context) { fun handleLoading(data: LoadingData) { if (data.isLoading) { - binding.vLoading.setMessage(data.messageId) binding.vLoading.setProgress(data) if (isShowing.not()) show() } else { diff --git a/core/src/main/java/org/futo/circles/core/view/LoadingView.kt b/core/src/main/java/org/futo/circles/core/view/LoadingView.kt index d1a3a48589669ce47217b518a62aa9e880cf0209..e64388d70da928a3414d552c483ceef629b41188 100644 --- a/core/src/main/java/org/futo/circles/core/view/LoadingView.kt +++ b/core/src/main/java/org/futo/circles/core/view/LoadingView.kt @@ -3,7 +3,6 @@ package org.futo.circles.core.view import android.content.Context import android.util.AttributeSet import android.view.LayoutInflater -import androidx.annotation.StringRes import androidx.constraintlayout.widget.ConstraintLayout import org.futo.circles.core.databinding.ViewLoadingBinding import org.futo.circles.core.extensions.setIsVisible @@ -18,16 +17,14 @@ class LoadingView( ViewLoadingBinding.inflate(LayoutInflater.from(context), this) - fun setMessage(@StringRes messageId: Int) { - binding.tvLoadingMessage.setText(messageId) - } - fun setProgress(data: LoadingData) { with(binding) { - setMessage(data.messageId) - horizontalProgress.max = data.total - horizontalProgress.progress = data.progress - horizontalProgress.setIsVisible(data.total != data.progress) + tvLoadingMessage.setText(data.messageId) + horizontalProgress.apply { + setIsVisible(data.total != data.progress) + max = data.total + progress = data.progress + } } } } \ No newline at end of file diff --git a/core/src/main/java/org/futo/circles/core/workspace/SharedCircleDataSource.kt b/core/src/main/java/org/futo/circles/core/workspace/SharedCircleDataSource.kt new file mode 100644 index 0000000000000000000000000000000000000000..abf48e67954807499b1b3a585822eef1c9b06c54 --- /dev/null +++ b/core/src/main/java/org/futo/circles/core/workspace/SharedCircleDataSource.kt @@ -0,0 +1,43 @@ +package org.futo.circles.core.workspace + +import org.futo.circles.core.extensions.getRoomOwners +import org.futo.circles.core.model.PROFILE_SPACE_ACCOUNT_DATA_KEY +import org.futo.circles.core.provider.MatrixSessionProvider +import org.futo.circles.core.room.RoomRelationsBuilder +import org.futo.circles.core.utils.getTimelineRoomFor +import org.matrix.android.sdk.api.session.getRoomSummary +import org.matrix.android.sdk.api.session.room.model.Membership +import org.matrix.android.sdk.api.session.room.model.RoomType +import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams +import javax.inject.Inject + +class SharedCircleDataSource @Inject constructor( + private val spacesTreeAccountDataSource: SpacesTreeAccountDataSource, + private val roomRelationsBuilder: RoomRelationsBuilder +) { + + fun getSharedCirclesSpaceId() = + spacesTreeAccountDataSource.getRoomIdByKey(PROFILE_SPACE_ACCOUNT_DATA_KEY) + + suspend fun addToSharedCircles(timelineId: String) { + getSharedCirclesSpaceId()?.let { roomRelationsBuilder.setRelations(timelineId, it) } + } + + suspend fun removeFromSharedCircles(timelineId: String) { + getSharedCirclesSpaceId()?.let { roomRelationsBuilder.removeRelations(timelineId, it) } + } + + fun getSharedCircleFor(userId: String) = MatrixSessionProvider.currentSession?.roomService() + ?.getRoomSummaries(roomSummaryQueryParams { excludeType = null })?.firstOrNull { summary -> + summary.roomType == RoomType.SPACE && summary.membership == Membership.JOIN && + getRoomOwners(summary.roomId).map { it.userId }.contains(userId) + } + + fun isCircleShared(circleId: String): Boolean { + val timelineId = getTimelineRoomFor(circleId)?.roomId + val sharedCirclesTimelinesIds = getSharedCirclesSpaceId()?.let { + MatrixSessionProvider.currentSession?.getRoomSummary(it)?.spaceChildren?.map { it.childRoomId } + } ?: emptyList() + return sharedCirclesTimelinesIds.contains(timelineId) + } +} \ No newline at end of file diff --git a/core/src/main/java/org/futo/circles/core/workspace/SpacesTreeAccountDataSource.kt b/core/src/main/java/org/futo/circles/core/workspace/SpacesTreeAccountDataSource.kt new file mode 100644 index 0000000000000000000000000000000000000000..86e2172185aa859cbf3e4a519c03b67627960298 --- /dev/null +++ b/core/src/main/java/org/futo/circles/core/workspace/SpacesTreeAccountDataSource.kt @@ -0,0 +1,28 @@ +package org.futo.circles.core.workspace + +import org.futo.circles.core.provider.MatrixSessionProvider +import javax.inject.Inject + +class SpacesTreeAccountDataSource @Inject constructor() { + + private fun getSpacesTreeConfig() = + MatrixSessionProvider.currentSession?.accountDataService() + ?.getUserAccountDataEvent(SPACES_CONFIG_KEY)?.content ?: emptyMap() + + suspend fun updateSpacesConfigAccountData(key: String, roomId: String) { + val currentConfig = getSpacesTreeConfig().toMutableMap() + currentConfig[key] = roomId + saveSpacesTreeConfig(currentConfig) + } + + fun getRoomIdByKey(key: String) = getSpacesTreeConfig()[key]?.toString() + + private suspend fun saveSpacesTreeConfig(configMap: Map<String, Any>) { + MatrixSessionProvider.getSessionOrThrow().accountDataService() + .updateUserAccountData(SPACES_CONFIG_KEY, configMap) + } + + companion object { + private const val SPACES_CONFIG_KEY = "org.futo.circles.config" + } +} \ No newline at end of file diff --git a/core/src/main/res/layout/dialog_fragment_system_notices.xml b/core/src/main/res/layout/dialog_fragment_system_notices.xml deleted file mode 100644 index 962a1815ad46e02c95373e5069734a72db7fc462..0000000000000000000000000000000000000000 --- a/core/src/main/res/layout/dialog_fragment_system_notices.xml +++ /dev/null @@ -1,39 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" - android:layout_width="match_parent" - android:layout_height="match_parent"> - - <com.google.android.material.appbar.MaterialToolbar - android:id="@+id/toolbar" - android:layout_width="0dp" - android:layout_height="?attr/actionBarSize" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" - app:navigationIcon="?attr/homeAsUpIndicator" - app:title="@string/system_notices" - app:titleCentered="true" /> - - <View - android:id="@+id/toolbarDivider" - android:layout_width="0dp" - android:layout_height="@dimen/divider_height" - android:background="@color/divider_color" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/toolbar" /> - - <androidx.recyclerview.widget.RecyclerView - android:id="@+id/rvTimeline" - android:layout_width="0dp" - android:layout_height="0dp" - android:clipChildren="false" - android:clipToPadding="false" - app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/toolbarDivider" /> - -</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/core/src/main/res/layout/list_item_system_notices.xml b/core/src/main/res/layout/list_item_system_notices.xml deleted file mode 100644 index 1bacb774fe10628bffc4d44b35c96d560f0d6031..0000000000000000000000000000000000000000 --- a/core/src/main/res/layout/list_item_system_notices.xml +++ /dev/null @@ -1,46 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<androidx.constraintlayout.widget.ConstraintLayout 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="wrap_content" - android:layout_marginStart="8dp" - android:layout_marginTop="8dp" - android:layout_marginEnd="36dp"> - - <com.google.android.material.imageview.ShapeableImageView - android:id="@+id/ivBackground" - android:layout_width="0dp" - android:layout_height="0dp" - android:background="@color/chip_selected_color" - app:layout_constraintBottom_toBottomOf="@id/tvTime" - app:layout_constraintEnd_toEndOf="@id/tvMessage" - app:layout_constraintStart_toStartOf="@id/tvMessage" - app:layout_constraintTop_toTopOf="@id/tvMessage" - app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.App.Message" /> - - <TextView - android:id="@+id/tvMessage" - style="@style/body" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:autoLink="web" - android:padding="8dp" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" - tools:text="sadasdasdasdasdasdasdasdasdasd" /> - - <TextView - android:id="@+id/tvTime" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_marginEnd="8dp" - android:paddingBottom="4dp" - android:textSize="12sp" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintTop_toBottomOf="@id/tvMessage" - tools:text="sadasdasdasdasdasdasdasdasdasd" /> - -</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/core/src/main/res/navigation/timeline_options_nav_graph.xml b/core/src/main/res/navigation/timeline_options_nav_graph.xml index 8a250f7a649b591bd2f49585beab3cbdbc1dda2f..be057a07db03101d59b976926e40fe97abb7db6e 100644 --- a/core/src/main/res/navigation/timeline_options_nav_graph.xml +++ b/core/src/main/res/navigation/timeline_options_nav_graph.xml @@ -192,7 +192,7 @@ </dialog> <dialog android:id="@+id/followingDialogFragment" - android:name="org.futo.circles.feature.circles.following.FollowingDialogFragment" + android:name="org.futo.circles.core.room.circles.following.FollowingDialogFragment" android:label="FollowingDialogFragment" tools:layout="@layout/dialog_fragment_following"> diff --git a/core/src/main/res/values/color.xml b/core/src/main/res/values/color.xml index 26ce318f8d0e7d1b4b2d0132b54b995b7dcc6ffb..7f2f935afb90f1b07f2efa16fab896646a04aef0 100644 --- a/core/src/main/res/values/color.xml +++ b/core/src/main/res/values/color.xml @@ -7,6 +7,7 @@ <color name="purple_700">#FF3700B3</color> <color name="teal_700">#FF018786</color> <color name="black">#FF000000</color> + <color name="yellow">#FFCC00</color> <color name="white">#FFFFFFFF</color> <color name="red">#FF3B30</color> <color name="divider_color">#ddd</color> diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index 5c4f97558b5cc934df2cb5afd1d3853c1a1daf1a..9d39d6f217cc0cfb5076c7ecb97080cee3eb19f2 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -22,7 +22,6 @@ <string name="moderator">Moderator</string> <string name="user">User</string> <string name="read_only">Read-only</string> - <string name="configuring_workspace">Configuring workspace</string> <string name="photos">Photos</string> <string name="loading">Loading</string> <string name="root_space_name">Circles</string> @@ -30,6 +29,7 @@ <string name="shared_circles">Shared Circles</string> <string name="photos_space_name">My Photo Galleries</string> <string name="groups_space_name">My Groups</string> + <string name="peopel_space_name">People</string> <string name="known_users">Known users</string> <string name="suggestions">Suggestions</string> <string name="no_results">No results</string> @@ -56,8 +56,6 @@ <string name="choose_gallery">Choose gallery</string> <string name="pick_media">Pick media</string> <string name="change_icon">Change icon</string> - <string name="system_notices">System notices</string> - <string name="system_notices_room_not_found">System notices room not found.</string> <string name="account">Account</string> <string name="clear_cache_and_reload">Clear cache and reload</string> <string name="deactivate_my_account">Deactivate my account</string> @@ -129,5 +127,18 @@ <string name="decline">Decline</string> <string name="requested_to_join_format">%s requested to join</string> <string name="invited_by_format">Invited by %s</string> - + <string name="circle_encryption_warning">NOTE: Circle name and cover image are not encrypted</string> + <string name="circle_name">Circle name</string> + <string name="circle_type">Circle type</string> + <string name="public_type">Public</string> + <string name="public_circle_explanation">Other users can ask to join</string> + <string name="private_type">Private</string> + <string name="private_circle_explanation">Accessible only by your invitation</string> + <string name="gallery_name">Gallery name</string> + <string name="gallery_encryption_warning">NOTE: Gallery name and cover image are not encrypted</string> + <string name="group_name">Group name</string> + <string name="group_encryption_warning">NOTE: Group name, topic and cover image are not encrypted</string> + <string name="group_topic">Group topic</string> + <string name="remove_from_this_circle_but_do_not_unfollow">Remove from this circle, but do not unfollow</string> + <string name="unfollow_completely_remove_from_all_circles">Unfollow completely (remove from all circles)</string> </resources> \ No newline at end of file diff --git a/gallery/src/main/java/org/futo/circles/gallery/feature/backup/MediaBackupDataSource.kt b/gallery/src/main/java/org/futo/circles/gallery/feature/backup/MediaBackupDataSource.kt index ea1352e1b8723fc636b644915e0d58f704995bda..53f3d22274b95e5a62f178e47a8fe89565ae97eb 100644 --- a/gallery/src/main/java/org/futo/circles/gallery/feature/backup/MediaBackupDataSource.kt +++ b/gallery/src/main/java/org/futo/circles/gallery/feature/backup/MediaBackupDataSource.kt @@ -6,12 +6,15 @@ import android.provider.MediaStore import dagger.hilt.android.qualifiers.ApplicationContext import org.futo.circles.core.model.Gallery import org.futo.circles.core.model.MediaType +import org.futo.circles.core.provider.MatrixSessionProvider import org.futo.circles.core.room.CreateRoomDataSource import org.futo.circles.core.timeline.post.SendMessageDataSource -import org.futo.circles.core.utils.getJoinedRoomIdByTag import org.futo.circles.gallery.model.MediaFolderListItem import org.futo.circles.gallery.model.MediaToBackupItem import org.futo.circles.gallery.model.toMediaToBackupItem +import org.matrix.android.sdk.api.session.getRoom +import org.matrix.android.sdk.api.session.room.model.Membership +import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams import java.io.File import javax.inject.Inject @@ -79,13 +82,22 @@ class MediaBackupDataSource @Inject constructor( var roomId = getJoinedRoomIdByTag(bucketId) if (roomId == null) { roomId = createRoomDataSource.createRoom( - circlesRoom = Gallery(tag = bucketId), + circlesRoom = Gallery(), name = getFolderNameBy(bucketId) ) + MatrixSessionProvider.currentSession?.getRoom(roomId)?.tagsService() + ?.addTag(bucketId, null) } return roomId } + private fun getJoinedRoomIdByTag(tag: String): String? { + val session = MatrixSessionProvider.currentSession ?: return null + return session.roomService().getRoomSummaries(roomSummaryQueryParams { + memberships = listOf(Membership.JOIN) + }).firstOrNull { it.hasTag(tag) }?.roomId + } + private fun getMediaCursor( selection: String? = null ): Cursor? { diff --git a/gallery/src/main/java/org/futo/circles/gallery/feature/backup/RoomAccountDataSource.kt b/gallery/src/main/java/org/futo/circles/gallery/feature/backup/RoomAccountDataSource.kt index c12c04964d126c6e9042eadf1a5bb8f54d846ab8..84a00d972f83f5d5a67022b3d8bb445f4188af89 100644 --- a/gallery/src/main/java/org/futo/circles/gallery/feature/backup/RoomAccountDataSource.kt +++ b/gallery/src/main/java/org/futo/circles/gallery/feature/backup/RoomAccountDataSource.kt @@ -3,8 +3,9 @@ package org.futo.circles.gallery.feature.backup import androidx.lifecycle.LiveData import androidx.lifecycle.map import org.futo.circles.core.extensions.createResult +import org.futo.circles.core.model.PHOTOS_SPACE_ACCOUNT_DATA_KEY import org.futo.circles.core.provider.MatrixSessionProvider -import org.futo.circles.core.utils.getPhotosSpaceId +import org.futo.circles.core.workspace.SpacesTreeAccountDataSource import org.futo.circles.gallery.model.MediaBackupSettingsData import org.futo.circles.gallery.model.toMediaBackupSettingsData import org.matrix.android.sdk.api.session.getRoom @@ -12,19 +13,25 @@ import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataEvent import org.matrix.android.sdk.api.util.Optional import javax.inject.Inject -class RoomAccountDataSource @Inject constructor() { +class RoomAccountDataSource @Inject constructor( + private val spacesTreeAccountDataSource: SpacesTreeAccountDataSource +) { + + private fun getPhotosSpaceId() = spacesTreeAccountDataSource.getRoomIdByKey( + PHOTOS_SPACE_ACCOUNT_DATA_KEY + ) ?: "" fun getMediaBackupSettingsLive() = - getAccountDataEventLive(getPhotosSpaceId() ?: "", ROOM_BACKUP_EVENT_TYPE)?.map { + getAccountDataEventLive(getPhotosSpaceId(), ROOM_BACKUP_EVENT_TYPE)?.map { it.getOrNull()?.content.toMediaBackupSettingsData() } fun getMediaBackupSettings() = - getAccountDataEvent(getPhotosSpaceId() ?: "", ROOM_BACKUP_EVENT_TYPE)?.content + getAccountDataEvent(getPhotosSpaceId(), ROOM_BACKUP_EVENT_TYPE)?.content .toMediaBackupSettingsData() suspend fun saveMediaBackupSettings(data: MediaBackupSettingsData) = updateRoomAccountData( - getPhotosSpaceId() ?: "", ROOM_BACKUP_EVENT_TYPE, data.toMap() + getPhotosSpaceId(), ROOM_BACKUP_EVENT_TYPE, data.toMap() ) fun getMediaBackupDateModified(roomId: String) = diff --git a/gallery/src/main/res/values/strings.xml b/gallery/src/main/res/values/strings.xml index 878656c6afa528bb23c360911e1bbf3636367889..6b0021488da69412bc5de1c450ee92cadbda0acd 100644 --- a/gallery/src/main/res/values/strings.xml +++ b/gallery/src/main/res/values/strings.xml @@ -14,10 +14,7 @@ <string name="compress_before_sending">Compress before sending</string> <string name="backup_device_folders">Backup device folders</string> <string name="backup_folders_hint">Choose folders to backup and view in your Gallery:</string> - <string name="gallery_name">Gallery name</string> - <string name="gallery_encryption_warning">NOTE: Gallery name and cover image are not encrypted</string> <string name="create_new_gallery">Create new gallery</string> - <string name="create">Create</string> <string name="photos_empty_message">Create your first Gallery</string> </resources> \ No newline at end of file