From 0059b7ff4f1c13c0d3cc46a43d61cc0e9dfe102e Mon Sep 17 00:00:00 2001 From: dece Date: Wed, 12 Apr 2023 19:56:16 +0200 Subject: [PATCH] app: use real Navigation component flow This fixes a lot of oddities in navigation, but also introduces UI changes, like moving the address bar to a specific sub-toolbar in the PageFragment. Unsure if this is the classiest choice but will do for now. Probably introduces more issues. --- app/build.gradle | 1 + .../lowrespalmtree/comet/HistoryFragment.kt | 4 +- .../dev/lowrespalmtree/comet/MainActivity.kt | 38 ++++++++++++------- .../dev/lowrespalmtree/comet/PageFragment.kt | 20 ++++++---- .../dev/lowrespalmtree/comet/PageViewModel.kt | 7 +++- app/src/main/res/layout/activity_main.xml | 31 +++++++++++---- .../res/layout/activity_main_nav_header.xml | 18 +++++++++ .../main/res/layout/fragment_page_view.xml | 5 +-- app/src/main/res/menu/drawer.xml | 5 --- app/src/main/res/navigation/main.xml | 28 ++++++++++++-- app/src/main/res/values/strings.xml | 3 ++ 11 files changed, 115 insertions(+), 45 deletions(-) create mode 100644 app/src/main/res/layout/activity_main_nav_header.xml diff --git a/app/build.gradle b/app/build.gradle index e5f9f69..439945a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -2,6 +2,7 @@ plugins { id 'com.android.application' id 'kotlin-android' id 'kotlin-kapt' + id 'androidx.navigation.safeargs.kotlin' } android { diff --git a/app/src/main/java/dev/lowrespalmtree/comet/HistoryFragment.kt b/app/src/main/java/dev/lowrespalmtree/comet/HistoryFragment.kt index 4844d8a..3ad86cc 100644 --- a/app/src/main/java/dev/lowrespalmtree/comet/HistoryFragment.kt +++ b/app/src/main/java/dev/lowrespalmtree/comet/HistoryFragment.kt @@ -4,7 +4,6 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.core.os.bundleOf import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import androidx.lifecycle.MutableLiveData @@ -46,8 +45,7 @@ class HistoryFragment : Fragment(), HistoryAdapter.Listener { } override fun onItemClick(url: String) { - val bundle = bundleOf("url" to url) - findNavController().navigate(R.id.action_global_pageFragment, bundle) + findNavController().navigate(PageFragmentDirections.actionGlobalPageFragment(url)) } class HistoryViewModel( diff --git a/app/src/main/java/dev/lowrespalmtree/comet/MainActivity.kt b/app/src/main/java/dev/lowrespalmtree/comet/MainActivity.kt index fc3ba1b..2665418 100644 --- a/app/src/main/java/dev/lowrespalmtree/comet/MainActivity.kt +++ b/app/src/main/java/dev/lowrespalmtree/comet/MainActivity.kt @@ -3,39 +3,51 @@ package dev.lowrespalmtree.comet import android.os.Bundle import android.util.Log import android.view.MenuItem +import androidx.appcompat.app.ActionBarDrawerToggle import androidx.appcompat.app.AppCompatActivity import androidx.core.os.bundleOf import androidx.navigation.fragment.NavHostFragment +import androidx.navigation.ui.setupActionBarWithNavController import androidx.navigation.ui.setupWithNavController import dev.lowrespalmtree.comet.databinding.ActivityMainBinding import kotlinx.coroutines.ExperimentalCoroutinesApi + @ExperimentalCoroutinesApi class MainActivity : AppCompatActivity() { - private lateinit var binding: ActivityMainBinding - private var nhf: NavHostFragment? = null + private val binding by lazy { ActivityMainBinding.inflate(layoutInflater) } + private val nhf by lazy { supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment } + private val navController by lazy { nhf.navController } override fun onCreate(savedInstanceState: Bundle?) { - Log.i(TAG, "onCreate") + Log.d(TAG, "onCreate") super.onCreate(savedInstanceState) - binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) + setSupportActionBar(binding.toolbar) Database.init(applicationContext) // TODO move to App Startup? - nhf = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment? - nhf?.also { binding.drawerNavigation.setupWithNavController(it.navController) } + val toggle = ActionBarDrawerToggle( + this, + binding.drawerLayout, + binding.toolbar, + R.string.navigation_drawer_open, + R.string.navigation_drawer_close + ) + binding.drawerLayout.addDrawerListener(toggle) + toggle.syncState() + setupActionBarWithNavController(navController, binding.drawerLayout) + binding.drawerNavigation.setupWithNavController(nhf.navController) } - /** Navigate to the PageViewFragment; this will automatically use the home URL if any. */ - fun goHome(@Suppress("unused_parameter") item: MenuItem) { - val bundle = bundleOf() - Preferences.getHomeUrl(this)?.let { bundle.putString("url", it) } - nhf?.navController?.navigate(R.id.action_global_pageFragment, bundle) - binding.drawerLayout.closeDrawers() - } +// /** Navigate to the PageViewFragment; this will automatically use the home URL if any. */ +// fun goHome(@Suppress("unused_parameter") item: MenuItem) { +// val bundle = bundleOf() +// Preferences.getHomeUrl(this)?.let { bundle.putString("url", it) } +// } companion object { private const val TAG = "MainActivity" } + } \ No newline at end of file diff --git a/app/src/main/java/dev/lowrespalmtree/comet/PageFragment.kt b/app/src/main/java/dev/lowrespalmtree/comet/PageFragment.kt index 7ad0e44..bbb959b 100644 --- a/app/src/main/java/dev/lowrespalmtree/comet/PageFragment.kt +++ b/app/src/main/java/dev/lowrespalmtree/comet/PageFragment.kt @@ -16,6 +16,7 @@ import androidx.activity.addCallback import androidx.appcompat.app.AlertDialog import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels +import androidx.navigation.fragment.navArgs import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.snackbar.Snackbar import dev.lowrespalmtree.comet.databinding.FragmentPageViewBinding @@ -26,6 +27,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi @ExperimentalCoroutinesApi class PageFragment : Fragment(), PageAdapter.Listener { private val vm: PageViewModel by viewModels() + private val args: PageFragmentArgs by navArgs() private lateinit var binding: FragmentPageViewBinding private lateinit var adapter: PageAdapter @@ -35,12 +37,12 @@ class PageFragment : Fragment(), PageAdapter.Listener { savedInstanceState: Bundle? ): View { Log.d(TAG, "onCreateView") - binding = FragmentPageViewBinding.inflate(layoutInflater) + binding = FragmentPageViewBinding.inflate(layoutInflater, container, false) return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - Log.d(TAG, "onViewCreated") + Log.d(TAG, "onViewCreated (args: ${args})") binding.contentRecycler.layoutManager = LinearLayoutManager(requireContext()) adapter = PageAdapter(this) binding.contentRecycler.adapter = adapter @@ -53,14 +55,15 @@ class PageFragment : Fragment(), PageAdapter.Listener { vm.lines.observe(viewLifecycleOwner) { updateLines(it.second, it.first) } vm.event.observe(viewLifecycleOwner) { handleEvent(it) } - activity?.onBackPressedDispatcher?.addCallback(viewLifecycleOwner) { onBackPressed() } + (activity as MainActivity?)?.let { + it.onBackPressedDispatcher.addCallback(viewLifecycleOwner) { onBackPressed() } + it.supportActionBar?.title = vm.currentTitle + } - val url = arguments?.getString("url") - if (!url.isNullOrEmpty()) { + val url = args.url + if (vm.currentUrl.isEmpty() && url.isNotEmpty()) { Log.d(TAG, "onViewCreated: open \"$url\"") openUrl(url) - } else if (vm.currentUrl.isNotEmpty()) { - Log.d(TAG, "onViewCreated: reuse current URL, probably fragment recreation") } else if (vm.visitedUrls.isEmpty()) { Log.d(TAG, "onViewCreated: no current URL, open home if configured") Preferences.getHomeUrl(requireContext())?.let { if (it.isNotBlank()) openUrl(it) } @@ -72,6 +75,7 @@ class PageFragment : Fragment(), PageAdapter.Listener { } private fun onBackPressed() { + Log.d(TAG, "onBackPressed") if (vm.visitedUrls.size >= 2) { vm.visitedUrls.removeLastOrNull() // Always remove current page first. vm.visitedUrls.removeLastOrNull()?.also { openUrl(it) } @@ -157,9 +161,11 @@ class PageFragment : Fragment(), PageAdapter.Listener { } is PageViewModel.SuccessEvent -> { vm.currentUrl = event.uri + vm.currentTitle = event.mainTitle ?: "" if (vm.visitedUrls.isEmpty() || vm.visitedUrls.last() != event.uri) vm.visitedUrls.add(event.uri) binding.addressBar.setText(event.uri) + (activity as MainActivity?)?.supportActionBar?.title = vm.currentTitle } is PageViewModel.BinaryEvent -> { // TODO this should present the user with options on what to do according to the diff --git a/app/src/main/java/dev/lowrespalmtree/comet/PageViewModel.kt b/app/src/main/java/dev/lowrespalmtree/comet/PageViewModel.kt index ae055ae..8484ef6 100644 --- a/app/src/main/java/dev/lowrespalmtree/comet/PageViewModel.kt +++ b/app/src/main/java/dev/lowrespalmtree/comet/PageViewModel.kt @@ -25,6 +25,9 @@ class PageViewModel( /** Currently viewed page URL. */ var currentUrl: String = "" + /** The first level 1 header of the current page (default is an empty string). */ + var currentTitle: String = "" + /** Latest Uri requested using `sendGeminiRequest`. */ var loadingUrl: Uri? = null @@ -58,7 +61,7 @@ class PageViewModel( data class InputEvent(val uri: Uri, val prompt: String) : Event() /** The server responded with a success code and *has finished* its response. */ - data class SuccessEvent(val uri: String) : Event() + data class SuccessEvent(val uri: String, val mainTitle: String?) : Event() /** The server responded with a success code and a binary MIME type (not delivered yet). */ data class BinaryEvent( @@ -243,7 +246,7 @@ class PageViewModel( // We record the history entry here: it's nice because we have the main title available // and we're already in a coroutine for database access. History.record(uriString, mainTitle) - event.postValue(SuccessEvent(uriString)) + event.postValue(SuccessEvent(uriString, mainTitle)) state.postValue(State.IDLE) } diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 855f214..3be5240 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,19 +1,33 @@ + android:fitsSystemWindows="true" + tools:openDrawer="start" + tools:context="dev.lowrespalmtree.comet.MainActivity"> - + android:orientation="vertical"> + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main_nav_header.xml b/app/src/main/res/layout/activity_main_nav_header.xml new file mode 100644 index 0000000..8e1c623 --- /dev/null +++ b/app/src/main/res/layout/activity_main_nav_header.xml @@ -0,0 +1,18 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_page_view.xml b/app/src/main/res/layout/fragment_page_view.xml index cb545f0..2fcad6f 100644 --- a/app/src/main/res/layout/fragment_page_view.xml +++ b/app/src/main/res/layout/fragment_page_view.xml @@ -4,13 +4,12 @@ xmlns:tools="http://schemas.android.com/tools" android:id="@+id/root" android:layout_width="match_parent" - android:layout_height="match_parent" - > + android:layout_height="match_parent"> + android:layout_height="48dp"> - + android:label=""> + + + android:label="@string/history" > + + + android:label="@string/identities" /> + + android:label="@string/settings" /> Open File downloaded. Image downloaded. + Open navigation drawer + Close navigation drawer + Logo \ No newline at end of file