Archived
Implemented navigation component; deleting an entry now shows a snack bar that allows for undo; edited several layouts
This commit is contained in:
@@ -1,19 +1,15 @@
|
||||
package com.denizd.textbasic.activity
|
||||
|
||||
import android.app.backup.BackupManager
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.content.ComponentName
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import com.denizd.textbasic.R
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.ui.setupWithNavController
|
||||
import com.denizd.textbasic.databinding.ActivityMainBinding
|
||||
import com.denizd.textbasic.fragment.GuideFragment
|
||||
import com.denizd.textbasic.fragment.QuoteFragment
|
||||
import com.denizd.textbasic.fragment.SettingsFragment
|
||||
import com.denizd.textbasic.widget.TextCanvasWidget
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
|
||||
@@ -24,57 +20,9 @@ class MainActivity : AppCompatActivity() {
|
||||
binding = ActivityMainBinding.inflate(this.layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
binding.buttonBackupUpload.setOnClickListener {
|
||||
BackupManager(this).dataChanged()
|
||||
Snackbar.make(binding.rootLayout, R.string.snack_backup_upload, Snackbar.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
binding.bottomNav.setOnItemSelectedListener { item ->
|
||||
loadFragment(item.itemId)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
if (supportFragmentManager.fragments.size == 0) {
|
||||
binding.bottomNav.selectedItemId = R.id.quotes
|
||||
loadFragment(R.id.quotes)
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadFragment(type: Int): Boolean {
|
||||
val fragment = when (type) {
|
||||
R.id.quotes -> QuoteFragment()
|
||||
R.id.guide -> GuideFragment()
|
||||
R.id.settings -> SettingsFragment()
|
||||
else -> QuoteFragment()
|
||||
}//supportFragmentManager.findFragmentByTag(type) ?: viewModel.getFragment(type)
|
||||
|
||||
if (supportFragmentManager.fragments.isNotEmpty() &&
|
||||
supportFragmentManager.fragments[supportFragmentManager.fragments.size-1]
|
||||
.tag?.equals(type.toString()) == true
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (fragment.lifecycle.currentState != Lifecycle.State.INITIALIZED) {
|
||||
return false
|
||||
}
|
||||
|
||||
supportFragmentManager.beginTransaction()
|
||||
.replace(R.id.fragment_container, fragment, type.toString())
|
||||
// .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
|
||||
.commit()
|
||||
|
||||
// with (supportFragmentManager) {
|
||||
// beginTransaction()
|
||||
// .hide(fragments[fragments.size - 1]) // should this be 0?
|
||||
// .show(findFragmentByTag(type) ?: TODO())
|
||||
// .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
|
||||
// .commit()
|
||||
// }
|
||||
return true
|
||||
binding.navView.setupWithNavController(
|
||||
binding.navHostFragmentContentMain.getFragment<NavHostFragment>().findNavController()
|
||||
)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
|
||||
@@ -5,14 +5,15 @@ import android.text.TextWatcher
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageButton
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.denizd.textbasic.R
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import java.util.Collections
|
||||
|
||||
class QuoteAdapter(
|
||||
quotes: List<String>,
|
||||
private val onDeleteListener: OnDeleteListener,
|
||||
) : RecyclerView.Adapter<QuoteAdapter.QuoteViewHolder>(),
|
||||
RecyclerRowMoveCallback.RecyclerViewTouchHelperContract {
|
||||
|
||||
@@ -20,8 +21,8 @@ class QuoteAdapter(
|
||||
|
||||
class QuoteViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
|
||||
val quote: TextView = view.findViewById(R.id.quote)
|
||||
val delete: ImageButton = view.findViewById(R.id.delete_button)
|
||||
val quote: TextView = view.findViewById(R.id.edit_text_quote)
|
||||
val delete: MaterialButton = view.findViewById(R.id.delete_button)
|
||||
}
|
||||
|
||||
// override fun getItemViewType(position: Int): Int {
|
||||
@@ -47,6 +48,7 @@ class QuoteAdapter(
|
||||
})
|
||||
|
||||
holder.delete.setOnClickListener {
|
||||
onDeleteListener.onDelete(mutableQuotes[holder.layoutPosition], holder.layoutPosition)
|
||||
mutableQuotes.removeAt(holder.layoutPosition)
|
||||
notifyItemRemoved(holder.layoutPosition)
|
||||
}
|
||||
@@ -59,6 +61,11 @@ class QuoteAdapter(
|
||||
notifyItemInserted(mutableQuotes.size + 1)
|
||||
}
|
||||
|
||||
fun addEntryAt(index: Int, entry: String) {
|
||||
mutableQuotes.add(index, entry)
|
||||
notifyItemInserted(index)
|
||||
}
|
||||
|
||||
fun getAllQuotes(): Array<String> {
|
||||
return mutableQuotes.filter { s -> s.isNotBlank() }.toTypedArray()
|
||||
}
|
||||
@@ -80,4 +87,8 @@ class QuoteAdapter(
|
||||
override fun onRowClear(viewHolder: QuoteViewHolder) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
interface OnDeleteListener {
|
||||
fun onDelete(entry: String, index: Int)
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.denizd.textbasic.fragment
|
||||
|
||||
import android.animation.LayoutTransition
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
@@ -11,40 +10,40 @@ import com.denizd.textbasic.util.viewBinding
|
||||
import com.denizd.textbasic.R
|
||||
import com.denizd.textbasic.adapter.RecyclerRowMoveCallback
|
||||
import com.denizd.textbasic.databinding.FragmentQuoteBinding
|
||||
import com.google.android.material.transition.MaterialSharedAxis
|
||||
import com.denizd.textbasic.util.showSnackBar
|
||||
|
||||
class QuoteFragment : BaseFragment(R.layout.fragment_quote) {
|
||||
class QuoteFragment : BaseFragment(R.layout.fragment_quote), QuoteAdapter.OnDeleteListener {
|
||||
|
||||
private lateinit var storage: QuoteStorage
|
||||
private lateinit var quoteAdapter: QuoteAdapter
|
||||
|
||||
private val binding: FragmentQuoteBinding by viewBinding(FragmentQuoteBinding::bind)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
exitTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true)
|
||||
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false)
|
||||
|
||||
enterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false)
|
||||
returnTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
binding.quoteConstraintLayout.layoutTransition.enableTransitionType(LayoutTransition.CHANGING)
|
||||
|
||||
storage = QuoteStorage(context)
|
||||
quoteAdapter = QuoteAdapter(storage.getAllQuotes())
|
||||
quoteAdapter = QuoteAdapter(storage.getAllQuotes(), this)
|
||||
|
||||
binding.quoteScroller.let { s ->
|
||||
s.layoutManager = LinearLayoutManager(context)
|
||||
ItemTouchHelper(RecyclerRowMoveCallback(quoteAdapter)).attachToRecyclerView(s)
|
||||
s.adapter = quoteAdapter
|
||||
binding.recyclerView.layoutManager = LinearLayoutManager(context)
|
||||
ItemTouchHelper(RecyclerRowMoveCallback(quoteAdapter))
|
||||
.attachToRecyclerView(binding.recyclerView)
|
||||
binding.recyclerView.adapter = quoteAdapter
|
||||
|
||||
// Set up scroll change listener to shrink and extend FAB accordingly
|
||||
binding.recyclerView.setOnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
|
||||
// Calculate the vertical scroll difference
|
||||
val dy = scrollY - oldScrollY
|
||||
if (dy > 0) {
|
||||
// If scrolling down, shrink the FAB
|
||||
binding.fabAddQuote.shrink()
|
||||
} else if (dy < 0) {
|
||||
// If scrolling up, extend the FAB
|
||||
binding.fabAddQuote.extend()
|
||||
}
|
||||
}
|
||||
|
||||
binding.addFab.setOnClickListener {
|
||||
binding.fabAddQuote.setOnClickListener {
|
||||
quoteAdapter.addNewQuote()
|
||||
}
|
||||
}
|
||||
@@ -57,4 +56,15 @@ class QuoteFragment : BaseFragment(R.layout.fragment_quote) {
|
||||
save()
|
||||
super.onPause()
|
||||
}
|
||||
|
||||
override fun onDelete(entry: String, index: Int) {
|
||||
context.theme.showSnackBar(
|
||||
binding.coordinatorLayout,
|
||||
getString(R.string.quote_fragment_snack_text),
|
||||
null,
|
||||
getString(R.string.quote_fragment_snack_undo),
|
||||
) {
|
||||
quoteAdapter.addEntryAt(index, entry)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.denizd.textbasic.util
|
||||
|
||||
import android.content.res.Resources
|
||||
import android.util.TypedValue
|
||||
import android.view.View
|
||||
import androidx.annotation.AttrRes
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
|
||||
/**
|
||||
* Retrieves a specified colour customised to the currently applied theme.
|
||||
*
|
||||
* @param id attribute ID of the colour reference
|
||||
* @return resolved colour
|
||||
*/
|
||||
fun Resources.Theme.getThemedColor(@AttrRes id: Int): Int = TypedValue().also { value ->
|
||||
resolveAttribute(id, value, true)
|
||||
}.data
|
||||
|
||||
/**
|
||||
* Show a snack bar. Colours will be applied according to the theme given.
|
||||
*
|
||||
* @receiver theme to apply colours of
|
||||
* @param view view where the snack bar will be shown in
|
||||
* @param text text to present in the snack bar
|
||||
* @param anchor view to anchor the snack bar to
|
||||
* @param actionText text to show on the action button; button will only be shown if a value is
|
||||
* passed here
|
||||
* @param action action to execute if the action button is pressed
|
||||
*/
|
||||
fun Resources.Theme.showSnackBar(
|
||||
view: CoordinatorLayout,
|
||||
text: String,
|
||||
anchor: View? = null,
|
||||
actionText: String = "",
|
||||
action: () -> Unit = {},
|
||||
) {
|
||||
val s = Snackbar.make(view, text, Snackbar.LENGTH_SHORT)
|
||||
// Set colours
|
||||
.setTextColor(getThemedColor(com.google.android.material.R.attr.colorOnSurfaceInverse))
|
||||
.setBackgroundTint(getThemedColor(com.google.android.material.R.attr.colorSurfaceInverse))
|
||||
|
||||
if (actionText.isNotBlank()) {
|
||||
// Set action, if a value for the text has been passed
|
||||
s.setAction(actionText) {
|
||||
action()
|
||||
}
|
||||
|
||||
// Show this snack bar for a longer time for the user to have a chance to react
|
||||
s.duration = Snackbar.LENGTH_LONG
|
||||
}
|
||||
|
||||
// Set anchor view, if one has been passed
|
||||
anchor?.let { a -> s.setAnchorView(a) }
|
||||
s.show()
|
||||
}
|
||||
Reference in New Issue
Block a user