diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index da3c56829586..7be81f621b06 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -285,10 +285,6 @@ - diff --git a/app/src/main/java/com/nextcloud/client/di/ComponentsModule.java b/app/src/main/java/com/nextcloud/client/di/ComponentsModule.java index e36fd021a447..c2e55a52afa1 100644 --- a/app/src/main/java/com/nextcloud/client/di/ComponentsModule.java +++ b/app/src/main/java/com/nextcloud/client/di/ComponentsModule.java @@ -47,7 +47,6 @@ import com.owncloud.android.services.AccountManagerService; import com.owncloud.android.services.OperationsService; import com.owncloud.android.syncadapter.FileSyncService; -import com.owncloud.android.ui.activities.ActivitiesActivity; import com.owncloud.android.ui.activity.BaseActivity; import com.owncloud.android.ui.activity.ConflictsResolveActivity; import com.owncloud.android.ui.activity.ContactsPreferenceActivity; @@ -101,6 +100,7 @@ import com.owncloud.android.ui.dialog.TermsOfServiceDialog; import com.owncloud.android.ui.dialog.ThemeSelectionDialog; import com.owncloud.android.ui.dialog.setupEncryption.SetupEncryptionDialogFragment; +import com.owncloud.android.ui.fragment.ActivitiesFragment; import com.owncloud.android.ui.fragment.ExtendedListFragment; import com.owncloud.android.ui.fragment.FeatureFragment; import com.owncloud.android.ui.fragment.FileDetailActivitiesFragment; @@ -142,7 +142,7 @@ @Module abstract class ComponentsModule { @ContributesAndroidInjector - abstract ActivitiesActivity activitiesActivity(); + abstract ActivitiesFragment activitiesFragment(); @ContributesAndroidInjector abstract AuthenticatorActivity authenticatorActivity(); diff --git a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java index a0a567d31163..cff5cb42600a 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java @@ -89,7 +89,6 @@ import com.owncloud.android.lib.resources.status.OCCapability; import com.owncloud.android.lib.resources.users.GetUserInfoRemoteOperation; import com.owncloud.android.operations.GetCapabilitiesOperation; -import com.owncloud.android.ui.activities.ActivitiesActivity; import com.owncloud.android.ui.events.AccountRemovedEvent; import com.owncloud.android.ui.events.ChangeMenuEvent; import com.owncloud.android.ui.events.SearchEvent; @@ -626,7 +625,7 @@ private void onNavigationItemClicked(final MenuItem menuItem) { startActivity(TrashbinActivity.class, Intent.FLAG_ACTIVITY_CLEAR_TOP); } else if (itemId == R.id.nav_activity) { resetOnlyPersonalAndOnDevice(); - startActivity(ActivitiesActivity.class, Intent.FLAG_ACTIVITY_CLEAR_TOP); + pushFragment(NavigatorScreen.Activities.INSTANCE); } else if (itemId == R.id.nav_settings) { resetOnlyPersonalAndOnDevice(); final Intent intent = new Intent(this, SettingsActivity.class); diff --git a/app/src/main/java/com/owncloud/android/ui/activities/ActivitiesActivity.kt b/app/src/main/java/com/owncloud/android/ui/fragment/ActivitiesFragment.kt similarity index 59% rename from app/src/main/java/com/owncloud/android/ui/activities/ActivitiesActivity.kt rename to app/src/main/java/com/owncloud/android/ui/fragment/ActivitiesFragment.kt index d217eaafd5d5..add303d5b88b 100644 --- a/app/src/main/java/com/owncloud/android/ui/activities/ActivitiesActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/ActivitiesFragment.kt @@ -2,102 +2,102 @@ * Nextcloud - Android Client * * SPDX-FileCopyrightText: 2026 Alper Ozturk - * SPDX-FileCopyrightText: 2018 Edvard Holst - * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only + * SPDX-License-Identifier: AGPL-3.0-or-later */ -package com.owncloud.android.ui.activities +package com.owncloud.android.ui.fragment import android.content.Intent import android.os.Bundle -import android.view.MenuItem +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.core.view.size +import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView +import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.network.ConnectivityService import com.nextcloud.common.NextcloudClient import com.owncloud.android.R -import com.owncloud.android.databinding.ActivityListLayoutBinding +import com.owncloud.android.databinding.FragmentActivitiesBinding import com.owncloud.android.datamodel.OCFile -import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.lib.resources.activities.model.RichObject import com.owncloud.android.lib.resources.files.FileUtils +import com.owncloud.android.ui.activities.ActivitiesContract +import com.owncloud.android.ui.activities.ActivitiesPresenter +import com.owncloud.android.ui.activities.adapter.ActivityListAdapter import com.owncloud.android.ui.activities.data.activities.ActivitiesRepository import com.owncloud.android.ui.activities.data.files.FilesRepository -import com.owncloud.android.ui.activity.DrawerActivity import com.owncloud.android.ui.activity.FileActivity import com.owncloud.android.ui.activity.FileDisplayActivity -import com.owncloud.android.ui.activities.adapter.ActivityListAdapter import com.owncloud.android.ui.interfaces.ActivityListInterface +import com.owncloud.android.ui.navigation.NavigatorActivity import com.owncloud.android.ui.preview.PreviewImageActivity import com.owncloud.android.ui.preview.PreviewImageFragment.Companion.canBePreviewed import com.owncloud.android.utils.DisplayUtils -import java.util.function.Supplier +import com.owncloud.android.utils.theme.ViewThemeUtils import javax.inject.Inject @Suppress("MagicNumber") -class ActivitiesActivity : - DrawerActivity(), +class ActivitiesFragment : + Fragment(), ActivityListInterface, ActivitiesContract.View { - var binding: ActivityListLayoutBinding? = null - private var adapter: ActivityListAdapter? = null - private var lastGiven: Long = 0 - private var isLoadingActivities = false - private var actionListener: ActivitiesContract.ActionListener? = null @Inject lateinit var activitiesRepository: ActivitiesRepository + @Inject + lateinit var viewThemeUtils: ViewThemeUtils + @Inject lateinit var filesRepository: FilesRepository @Inject lateinit var connectivityService: ConnectivityService - override fun onCreate(savedInstanceState: Bundle?) { - Log_OC.v(TAG, "onCreate() start") - super.onCreate(savedInstanceState) - - actionListener = ActivitiesPresenter(activitiesRepository, filesRepository, this) - - binding = ActivityListLayoutBinding.inflate(layoutInflater) - setContentView(binding?.getRoot()) + @Inject + lateinit var userAccountManager: UserAccountManager - setupToolbar() + private var _binding: FragmentActivitiesBinding? = null + private val binding get() = _binding!! - binding?.swipeContainingList?.let { viewThemeUtils.androidx.themeSwipeRefreshLayout(it) } + private var adapter: ActivityListAdapter? = null + private var lastGiven: Long = 0 + private var isLoadingActivities = false + private var actionListener: ActivitiesContract.ActionListener? = null - setupDrawer(menuItemId) - updateActionBarTitleAndHomeButtonByString(getString(R.string.drawer_item_activities)) + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + _binding = FragmentActivitiesBinding.inflate(inflater, container, false) + return binding.root + } - binding?.swipeContainingList?.setOnRefreshListener { - // We set lastGiven variable to undefined here since when manually refreshing - // activities data we want to clear the list and reset the pagination. + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + actionListener = ActivitiesPresenter(activitiesRepository, filesRepository, this) + viewThemeUtils.androidx.themeSwipeRefreshLayout(binding.swipeContainingList) + binding.swipeContainingList.setOnRefreshListener { lastGiven = ActivitiesContract.ActionListener.UNDEFINED.toLong() actionListener?.loadActivities(lifecycleScope, lastGiven) } + setupContent() } - override fun getMenuItemId(): Int = R.id.nav_activity - - @Suppress("MagicNumber") private fun setupContent() { - binding?.emptyList?.emptyListIcon?.setImageResource(R.drawable.ic_activity) + binding.emptyList.emptyListIcon.setImageResource(R.drawable.ic_activity) adapter = ActivityListAdapter( - this, + requireActivity(), userAccountManager, this, false, viewThemeUtils ) - binding?.list?.setAdapter(adapter) - - val layoutManager = LinearLayoutManager(this) + binding.list.adapter = adapter - binding?.list?.run { + val layoutManager = LinearLayoutManager(requireContext()) + binding.list.run { setLayoutManager(layoutManager) addOnScrollListener(getOnScrollListener(layoutManager)) } @@ -108,43 +108,33 @@ class ActivitiesActivity : private fun getOnScrollListener(layoutManager: LinearLayoutManager) = object : RecyclerView.OnScrollListener() { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { super.onScrolled(recyclerView, dx, dy) - val visibleItemCount = recyclerView.size - val totalItemCount = layoutManager.getItemCount() + val totalItemCount = layoutManager.itemCount val firstVisibleItemIndex = layoutManager.findFirstVisibleItemPosition() - // synchronize loading state when item count changes - if (!isLoadingActivities && (totalItemCount - visibleItemCount) <= (firstVisibleItemIndex + 5) && + if (!isLoadingActivities && + (totalItemCount - visibleItemCount) <= (firstVisibleItemIndex + 5) && lastGiven > 0 ) { - // Almost reached the end, continue to load new activities actionListener?.loadActivities(lifecycleScope, lastGiven) } } } - override fun onOptionsItemSelected(item: MenuItem): Boolean = if (item.itemId == android.R.id.home) { - if (isDrawerOpen) { - closeDrawer() - } else { - openDrawer() - } - true - } else { - Log_OC.w(TAG, "Unknown menu item triggered") - super.onOptionsItemSelected(item) - } - override fun onResume() { super.onResume() - highlightNavigationViewItem(menuItemId) actionListener?.onResume() - setupContent() + } + + override fun onStop() { + super.onStop() + actionListener?.onStop() } override fun onActivityClicked(richObject: RichObject) { val path = FileUtils.PATH_SEPARATOR + richObject.path - actionListener?.openActivity(path, this) + val baseActivity = requireActivity() as NavigatorActivity + actionListener?.openActivity(path, baseActivity) } override fun showActivities(activities: List, client: NextcloudClient, lastGiven: Long) { @@ -152,69 +142,65 @@ class ActivitiesActivity : adapter?.setActivityItems(activities, client, clear) this.lastGiven = lastGiven - // Hide the recyclerView if list is empty if (adapter?.isEmpty() == true) { showEmptyContent( getString(R.string.activities_no_results_headline), getString(R.string.activities_no_results_message) ) - binding?.loadingContent?.visibility = View.GONE - binding?.list?.visibility = View.GONE + binding.loadingContent.visibility = View.GONE + binding.list.visibility = View.GONE } else { - binding?.emptyList?.emptyListView?.visibility = View.GONE - binding?.loadingContent?.visibility = View.GONE - binding?.list?.visibility = View.VISIBLE + binding.emptyList.emptyListView.visibility = View.GONE + binding.loadingContent.visibility = View.GONE + binding.list.visibility = View.VISIBLE } } override fun showActivitiesLoadError(error: String) { connectivityService.isNetworkAndServerAvailable { if (it) { - DisplayUtils.showSnackMessage(this, error) + DisplayUtils.showSnackMessage(requireView(), error) } else { showEmptyContent( getString(R.string.server_not_reachable), getString(R.string.server_not_reachable_content) ) - binding?.emptyList?.emptyListIcon?.setImageResource(R.drawable.ic_sync_off) + binding.emptyList.emptyListIcon.setImageResource(R.drawable.ic_sync_off) } } } override fun showActivityDetailUI(ocFile: OCFile) { + val user = userAccountManager.user val intent = if (canBePreviewed(ocFile)) { - Intent(baseContext, PreviewImageActivity::class.java) + Intent(requireContext(), PreviewImageActivity::class.java) } else { - Intent(baseContext, FileDisplayActivity::class.java) + Intent(requireContext(), FileDisplayActivity::class.java) }.apply { putExtra(FileActivity.EXTRA_FILE, ocFile) - putExtra( - FileActivity.EXTRA_USER, - user.orElseThrow(Supplier { RuntimeException() }) - ) + putExtra(FileActivity.EXTRA_USER, user) } - startActivity(intent) } override fun showActivityDetailUIIsNull() { - DisplayUtils.showSnackMessage(this, R.string.file_not_found) + DisplayUtils.showSnackMessage(requireView(), R.string.file_not_found) } override fun showActivityDetailError(error: String) { - DisplayUtils.showSnackMessage(this, error) + DisplayUtils.showSnackMessage(requireView(), error) } override fun showLoadingMessage() { - binding?.emptyList?.emptyListView?.visibility = View.GONE + binding.emptyList.emptyListView.visibility = View.GONE } override fun showEmptyContent(headline: String, message: String) { - binding?.run { + binding.run { emptyList.emptyListViewHeadline.text = headline emptyList.emptyListViewText.text = message loadingContent.visibility = View.GONE - emptyList.emptyListIcon.setVisibility(View.VISIBLE) + emptyList.emptyListIcon.visibility = View.VISIBLE emptyList.emptyListViewHeadline.visibility = View.VISIBLE emptyList.emptyListViewText.visibility = View.VISIBLE emptyList.emptyListView.visibility = View.VISIBLE @@ -224,16 +210,12 @@ class ActivitiesActivity : override fun setProgressIndicatorState(isActive: Boolean) { isLoadingActivities = isActive if (adapter?.isEmpty() == false) { - binding?.swipeContainingList?.post { binding?.swipeContainingList?.isRefreshing = isActive } + binding.swipeContainingList.post { binding.swipeContainingList.isRefreshing = isActive } } } - override fun onStop() { - super.onStop() - actionListener?.onStop() - } - - companion object { - private val TAG: String = ActivitiesActivity::class.java.getSimpleName() + override fun onDestroyView() { + super.onDestroyView() + _binding = null } } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/community/CommunityFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/community/CommunityFragment.kt index 3513519942ba..78fdf5933496 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/community/CommunityFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/community/CommunityFragment.kt @@ -16,15 +16,17 @@ import androidx.fragment.app.Fragment import com.nextcloud.utils.extensions.setHtmlContent import com.owncloud.android.R import com.owncloud.android.databinding.FragmentCommunityBinding -import com.owncloud.android.ui.activity.DrawerActivity import com.owncloud.android.utils.DisplayUtils +import com.owncloud.android.utils.theme.ViewThemeUtils +import javax.inject.Inject class CommunityFragment : Fragment() { private var _binding: FragmentCommunityBinding? = null private val binding get() = _binding!! - private val drawerActivity get() = activity as? DrawerActivity + @Inject + lateinit var viewThemeUtils: ViewThemeUtils override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { _binding = FragmentCommunityBinding.inflate(inflater, container, false) @@ -33,17 +35,13 @@ class CommunityFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - drawerActivity?.run { - setupToolbar() - updateActionBarTitleAndHomeButtonByString(getString(R.string.drawer_community)) - } binding.communityReleaseCandidateText.movementMethod = LinkMovementMethod.getInstance() - drawerActivity?.let { setupViews(it) } + setupViews() setOnClickListeners() } - private fun setupViews(activity: DrawerActivity) { - val primaryColor = activity.viewThemeUtils.files.primaryColorToHexString(requireContext()) + private fun setupViews() { + val primaryColor = viewThemeUtils.files.primaryColorToHexString(requireContext()) val helpLink = getString(R.string.help_link) val forum = getString(R.string.community_contribute_forum_forum) val translationLink = getString(R.string.translation_link) @@ -81,7 +79,7 @@ class CommunityFragment : Fragment() { view.setHtmlContent(content) } - activity.viewThemeUtils.material.colorMaterialButtonPrimaryFilled(binding.communityTestingReport) + viewThemeUtils.material.colorMaterialButtonPrimaryFilled(binding.communityTestingReport) binding.communityTestingReport.setOnClickListener { DisplayUtils.startLinkIntent(requireActivity(), R.string.report_issue_empty_link) } diff --git a/app/src/main/java/com/owncloud/android/ui/navigation/ActionBarStyle.kt b/app/src/main/java/com/owncloud/android/ui/navigation/ActionBarStyle.kt new file mode 100644 index 000000000000..ba3e371f87ee --- /dev/null +++ b/app/src/main/java/com/owncloud/android/ui/navigation/ActionBarStyle.kt @@ -0,0 +1,13 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2026 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.owncloud.android.ui.navigation + +enum class ActionBarStyle { + Plain, + Search +} diff --git a/app/src/main/java/com/owncloud/android/ui/navigation/Navigator.kt b/app/src/main/java/com/owncloud/android/ui/navigation/Navigator.kt index 7416661e8b17..01ba37b32ba7 100644 --- a/app/src/main/java/com/owncloud/android/ui/navigation/Navigator.kt +++ b/app/src/main/java/com/owncloud/android/ui/navigation/Navigator.kt @@ -10,18 +10,15 @@ package com.owncloud.android.ui.navigation import android.view.View import androidx.fragment.app.FragmentManager import com.owncloud.android.lib.common.utils.Log_OC -import com.owncloud.android.ui.fragment.community.CommunityFragment class Navigator(private val fragmentManager: FragmentManager, private val fragmentContainer: View) { companion object { private const val TAG = "Navigator" } - fun push(screen: NavigatorScreen) { - val fragment = when (screen) { - NavigatorScreen.Community -> CommunityFragment() - } + private val stack = ArrayDeque() + fun push(screen: NavigatorScreen) { if (fragmentManager.findFragmentByTag(screen.tag) != null) { Log_OC.d(TAG, "cannot push same fragment - ${screen.tag}") return @@ -29,13 +26,16 @@ class Navigator(private val fragmentManager: FragmentManager, private val fragme Log_OC.d(TAG, "pushing - ${screen.tag}") + stack.addLast(screen) fragmentManager.beginTransaction() - .replace(fragmentContainer.id, fragment, screen.tag) - .addToBackStack(screen::class.simpleName) + .replace(fragmentContainer.id, screen.toFragment()) + .addToBackStack(screen.tag) .commit() } - fun pop() { + fun pop(): NavigatorScreen? { + stack.removeLastOrNull() fragmentManager.popBackStack() + return stack.lastOrNull() } } diff --git a/app/src/main/java/com/owncloud/android/ui/navigation/NavigatorActivity.kt b/app/src/main/java/com/owncloud/android/ui/navigation/NavigatorActivity.kt index f51ceeda2857..69ff8c4f7f6c 100644 --- a/app/src/main/java/com/owncloud/android/ui/navigation/NavigatorActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/navigation/NavigatorActivity.kt @@ -16,6 +16,7 @@ import androidx.fragment.app.FragmentContainerView import com.nextcloud.utils.extensions.getParcelableArgument import com.owncloud.android.R import com.owncloud.android.ui.activity.DrawerActivity +import dagger.android.support.AndroidSupportInjection class NavigatorActivity : DrawerActivity() { @@ -24,21 +25,39 @@ class NavigatorActivity : DrawerActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_navigator) - setupToolbar() - setupDrawer(menuItemId) - setupBackPressedHandler() val screen = intent.getParcelableArgument(EXTRA_SCREEN, NavigatorScreen::class.java) ?: return val fragmentContainerView = findViewById(R.id.fragment_container_view) - navigator = Navigator(supportFragmentManager, fragmentContainerView) + + setupBackPressedHandler() push(screen) + supportFragmentManager.addFragmentOnAttachListener { _, fragment -> + AndroidSupportInjection.inject(fragment) + } + } + + fun pop() { + val previousScreen = navigator.pop() ?: return + setupActionBar(previousScreen) } fun push(screen: NavigatorScreen) { + setupActionBar(screen) navigator.push(screen) } + private fun setupActionBar(screen: NavigatorScreen) { + val (style, titleId) = screen.actionBarStyle() + if (style == ActionBarStyle.Plain) { + setupToolbar() + } else { + setupHomeSearchToolbarWithSortAndListButtons() + } + updateActionBarTitleAndHomeButtonByString(getString(titleId)) + setupDrawer(menuItemId) + } + private fun setupBackPressedHandler() { onBackPressedDispatcher.addCallback( this, @@ -47,7 +66,7 @@ class NavigatorActivity : DrawerActivity() { when { isDrawerOpen -> closeDrawer() supportFragmentManager.backStackEntryCount == 1 -> finish() - else -> navigator.pop() + else -> pop() } } } @@ -66,9 +85,9 @@ class NavigatorActivity : DrawerActivity() { return super.onOptionsItemSelected(item) } - override fun getMenuItemId(): Int = when (intent.getParcelableArgument(EXTRA_SCREEN, NavigatorScreen::class.java)) { - NavigatorScreen.Community -> R.id.nav_community - else -> super.getMenuItemId() + override fun getMenuItemId(): Int { + val screen = intent.getParcelableArgument(EXTRA_SCREEN, NavigatorScreen::class.java) + return screen?.menuItemId() ?: super.getMenuItemId() } override fun onResume() { diff --git a/app/src/main/java/com/owncloud/android/ui/navigation/NavigatorScreen.kt b/app/src/main/java/com/owncloud/android/ui/navigation/NavigatorScreen.kt index 4f07aab74f81..a1bfccafaf1e 100644 --- a/app/src/main/java/com/owncloud/android/ui/navigation/NavigatorScreen.kt +++ b/app/src/main/java/com/owncloud/android/ui/navigation/NavigatorScreen.kt @@ -8,10 +8,32 @@ package com.owncloud.android.ui.navigation import android.os.Parcelable +import androidx.fragment.app.Fragment +import com.owncloud.android.R +import com.owncloud.android.ui.fragment.ActivitiesFragment +import com.owncloud.android.ui.fragment.community.CommunityFragment import kotlinx.parcelize.Parcelize sealed class NavigatorScreen(val tag: String) : Parcelable { + @Parcelize + object Activities : NavigatorScreen("Activities") + @Parcelize object Community : NavigatorScreen("Community") + + fun menuItemId(): Int = when (this) { + Community -> R.id.nav_community + Activities -> R.id.nav_activity + } + + fun actionBarStyle(): Pair = when (this) { + Community -> ActionBarStyle.Plain to R.string.drawer_community + Activities -> ActionBarStyle.Plain to R.string.drawer_item_activities + } + + fun toFragment(): Fragment = when (this) { + Community -> CommunityFragment() + Activities -> ActivitiesFragment() + } } diff --git a/app/src/main/res/layout/activity_list_layout.xml b/app/src/main/res/layout/activity_list_layout.xml deleted file mode 100644 index 1c5699830dca..000000000000 --- a/app/src/main/res/layout/activity_list_layout.xml +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/fragment_activities.xml b/app/src/main/res/layout/fragment_activities.xml new file mode 100644 index 000000000000..07ee4f950c7d --- /dev/null +++ b/app/src/main/res/layout/fragment_activities.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +