mirror of
https://github.com/android-password-store/Android-Password-Store
synced 2025-08-31 22:35:17 +00:00
Introduce and switch to FragmentViewBindingDelegate (#797)
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
This commit is contained in:
@@ -80,6 +80,7 @@ dependencies {
|
||||
implementation deps.androidx.core_ktx
|
||||
implementation deps.androidx.documentfile
|
||||
implementation deps.androidx.fragment_ktx
|
||||
implementation deps.androidx.lifecycle_common
|
||||
implementation deps.androidx.lifecycle_livedata_ktx
|
||||
implementation deps.androidx.lifecycle_viewmodel_ktx
|
||||
implementation deps.androidx.local_broadcast_manager
|
||||
|
@@ -33,6 +33,7 @@ import com.zeapo.pwdstore.ui.adapters.PasswordItemRecyclerAdapter
|
||||
import com.zeapo.pwdstore.ui.dialogs.ItemCreationBottomSheet
|
||||
import com.zeapo.pwdstore.utils.PasswordItem
|
||||
import com.zeapo.pwdstore.utils.PasswordRepository
|
||||
import com.zeapo.pwdstore.utils.viewBinding
|
||||
import me.zhanghai.android.fastscroll.FastScrollerBuilder
|
||||
import java.io.File
|
||||
import java.util.Stack
|
||||
@@ -44,10 +45,9 @@ class PasswordFragment : Fragment() {
|
||||
|
||||
private var recyclerViewStateToRestore: Parcelable? = null
|
||||
private var actionMode: ActionMode? = null
|
||||
private var _binding: PasswordRecyclerViewBinding? = null
|
||||
|
||||
private val model: SearchableRepositoryViewModel by activityViewModels()
|
||||
private val binding get() = _binding!!
|
||||
private val binding by viewBinding(PasswordRecyclerViewBinding::bind)
|
||||
|
||||
private fun requireStore() = requireActivity() as PasswordStore
|
||||
|
||||
@@ -56,7 +56,6 @@ class PasswordFragment : Fragment() {
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
_binding = PasswordRecyclerViewBinding.inflate(inflater, container, false)
|
||||
settings = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
initializePasswordList()
|
||||
binding.fab.setOnClickListener {
|
||||
@@ -149,11 +148,6 @@ class PasswordFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
_binding = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
private val actionModeCallback = object : ActionMode.Callback {
|
||||
// Called when the action mode is created; startActionMode() was called
|
||||
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
|
||||
|
@@ -10,25 +10,19 @@ import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import kotlinx.android.synthetic.main.fragment_to_clone_or_not.clone_from_server_button
|
||||
import kotlinx.android.synthetic.main.fragment_to_clone_or_not.local_directory_button
|
||||
import kotlinx.android.synthetic.main.fragment_to_clone_or_not.settings_button
|
||||
import com.zeapo.pwdstore.databinding.FragmentToCloneOrNotBinding
|
||||
import com.zeapo.pwdstore.utils.viewBinding
|
||||
|
||||
class ToCloneOrNot : Fragment() {
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
// Inflate the layout for this fragment
|
||||
return inflater.inflate(R.layout.fragment_to_clone_or_not, container, false)
|
||||
}
|
||||
private val binding by viewBinding(FragmentToCloneOrNotBinding::bind)
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = binding.root
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
settings_button.setOnClickListener { startActivity(Intent(requireContext(), UserPreference::class.java)) }
|
||||
local_directory_button.setOnClickListener { (requireActivity() as PasswordStore).initRepository(PasswordStore.NEW_REPO_BUTTON) }
|
||||
clone_from_server_button.setOnClickListener { (requireActivity() as PasswordStore).initRepository(PasswordStore.CLONE_REPO_BUTTON) }
|
||||
binding.settingsButton.setOnClickListener { startActivity(Intent(requireContext(), UserPreference::class.java)) }
|
||||
binding.localDirectoryButton.setOnClickListener { (requireActivity() as PasswordStore).initRepository(PasswordStore.NEW_REPO_BUTTON) }
|
||||
binding.cloneFromServerButton.setOnClickListener { (requireActivity() as PasswordStore).initRepository(PasswordStore.CLONE_REPO_BUTTON) }
|
||||
}
|
||||
}
|
||||
|
@@ -36,6 +36,7 @@ import com.zeapo.pwdstore.autofill.oreo.DirectoryStructure
|
||||
import com.zeapo.pwdstore.autofill.oreo.FormOrigin
|
||||
import com.zeapo.pwdstore.databinding.ActivityOreoAutofillFilterBinding
|
||||
import com.zeapo.pwdstore.utils.PasswordItem
|
||||
import com.zeapo.pwdstore.utils.viewBinding
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.O)
|
||||
class AutofillFilterView : AppCompatActivity() {
|
||||
@@ -72,7 +73,7 @@ class AutofillFilterView : AppCompatActivity() {
|
||||
|
||||
private lateinit var formOrigin: FormOrigin
|
||||
private lateinit var directoryStructure: DirectoryStructure
|
||||
private lateinit var binding: ActivityOreoAutofillFilterBinding
|
||||
private val binding by viewBinding(ActivityOreoAutofillFilterBinding::inflate)
|
||||
|
||||
private val model: SearchableRepositoryViewModel by viewModels {
|
||||
ViewModelProvider.AndroidViewModelFactory(application)
|
||||
@@ -80,7 +81,6 @@ class AutofillFilterView : AppCompatActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivityOreoAutofillFilterBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
setFinishOnTouchOutside(true)
|
||||
|
||||
|
@@ -22,6 +22,7 @@ import com.zeapo.pwdstore.autofill.oreo.AutofillPublisherChangedException
|
||||
import com.zeapo.pwdstore.autofill.oreo.FormOrigin
|
||||
import com.zeapo.pwdstore.autofill.oreo.computeCertificatesHash
|
||||
import com.zeapo.pwdstore.databinding.ActivityOreoAutofillPublisherChangedBinding
|
||||
import com.zeapo.pwdstore.utils.viewBinding
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.O)
|
||||
class AutofillPublisherChangedActivity : AppCompatActivity() {
|
||||
@@ -45,11 +46,10 @@ class AutofillPublisherChangedActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
private lateinit var appPackage: String
|
||||
private lateinit var binding: ActivityOreoAutofillPublisherChangedBinding
|
||||
private val binding by viewBinding(ActivityOreoAutofillPublisherChangedBinding::inflate)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivityOreoAutofillPublisherChangedBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
setFinishOnTouchOutside(true)
|
||||
|
||||
|
@@ -14,15 +14,15 @@ import com.google.android.material.snackbar.Snackbar
|
||||
import com.zeapo.pwdstore.R
|
||||
import com.zeapo.pwdstore.databinding.ActivityGitConfigBinding
|
||||
import com.zeapo.pwdstore.utils.PasswordRepository
|
||||
import com.zeapo.pwdstore.utils.viewBinding
|
||||
import org.eclipse.jgit.lib.Constants
|
||||
|
||||
class GitConfigActivity : BaseGitActivity() {
|
||||
|
||||
private lateinit var binding: ActivityGitConfigBinding
|
||||
private val binding by viewBinding(ActivityGitConfigBinding::inflate)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivityGitConfigBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
|
||||
|
@@ -17,6 +17,7 @@ import com.zeapo.pwdstore.databinding.ActivityGitCloneBinding
|
||||
import com.zeapo.pwdstore.git.config.ConnectionMode
|
||||
import com.zeapo.pwdstore.git.config.Protocol
|
||||
import com.zeapo.pwdstore.utils.PasswordRepository
|
||||
import com.zeapo.pwdstore.utils.viewBinding
|
||||
import java.io.IOException
|
||||
|
||||
/**
|
||||
@@ -25,11 +26,10 @@ import java.io.IOException
|
||||
*/
|
||||
class GitServerConfigActivity : BaseGitActivity() {
|
||||
|
||||
private lateinit var binding: ActivityGitCloneBinding
|
||||
private val binding by viewBinding(ActivityGitCloneBinding::inflate)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivityGitCloneBinding.inflate(layoutInflater)
|
||||
val isClone = intent?.extras?.getInt(REQUEST_ARG_OP) ?: -1 == REQUEST_CLONE
|
||||
if (isClone) {
|
||||
binding.saveButton.text = getString(R.string.clone_button)
|
||||
|
@@ -19,6 +19,7 @@ import com.jcraft.jsch.JSch
|
||||
import com.jcraft.jsch.KeyPair
|
||||
import com.zeapo.pwdstore.R
|
||||
import com.zeapo.pwdstore.databinding.FragmentSshKeygenBinding
|
||||
import com.zeapo.pwdstore.utils.viewBinding
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
@@ -28,17 +29,9 @@ import java.io.FileOutputStream
|
||||
class SshKeyGenFragment : Fragment() {
|
||||
|
||||
private var keyLength = 4096
|
||||
private var _binding: FragmentSshKeygenBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
private val binding by viewBinding(FragmentSshKeygenBinding::bind)
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
_binding = FragmentSshKeygenBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?) = binding.root
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
@@ -60,7 +53,6 @@ class SshKeyGenFragment : Fragment() {
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
}
|
||||
|
||||
// Invoked when 'Generate' button of SshKeyGenFragment clicked. Generates a
|
||||
|
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
|
||||
* SPDX-License-Identifier: GPL-3.0-only
|
||||
*/
|
||||
|
||||
package com.zeapo.pwdstore.utils
|
||||
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.observe
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import kotlin.properties.ReadOnlyProperty
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
/**
|
||||
* Imported from https://medium.com/@Zhuinden/simple-one-liner-viewbinding-in-fragments-and-activities-with-kotlin-961430c6c07c
|
||||
*/
|
||||
class FragmentViewBindingDelegate<T : ViewBinding>(
|
||||
val fragment: Fragment,
|
||||
val viewBindingFactory: (View) -> T
|
||||
) : ReadOnlyProperty<Fragment, T> {
|
||||
|
||||
private var binding: T? = null
|
||||
|
||||
init {
|
||||
fragment.lifecycle.addObserver(object : DefaultLifecycleObserver {
|
||||
override fun onCreate(owner: LifecycleOwner) {
|
||||
fragment.viewLifecycleOwnerLiveData.observe(fragment) { viewLifecycleOwner ->
|
||||
viewLifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver {
|
||||
override fun onDestroy(owner: LifecycleOwner) {
|
||||
binding = null
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun getValue(thisRef: Fragment, property: KProperty<*>): T {
|
||||
val binding = binding
|
||||
if (binding != null) {
|
||||
return binding
|
||||
}
|
||||
|
||||
val lifecycle = fragment.viewLifecycleOwner.lifecycle
|
||||
if (!lifecycle.currentState.isAtLeast(Lifecycle.State.INITIALIZED)) {
|
||||
throw IllegalStateException("Should not attempt to get bindings when Fragment views are destroyed.")
|
||||
}
|
||||
|
||||
return viewBindingFactory(thisRef.requireView()).also { this.binding = it }
|
||||
}
|
||||
}
|
||||
|
||||
fun <T : ViewBinding> Fragment.viewBinding(viewBindingFactory: (View) -> T) =
|
||||
FragmentViewBindingDelegate(this, viewBindingFactory)
|
||||
|
||||
inline fun <T : ViewBinding> AppCompatActivity.viewBinding(crossinline bindingInflater: (LayoutInflater) -> T) =
|
||||
lazy(LazyThreadSafetyMode.NONE) {
|
||||
bindingInflater.invoke(layoutInflater)
|
||||
}
|
@@ -32,6 +32,7 @@ ext.deps = [
|
||||
core_ktx: 'androidx.core:core-ktx:1.3.0-rc01',
|
||||
documentfile: 'androidx.documentfile:documentfile:1.0.1',
|
||||
fragment_ktx: 'androidx.fragment:fragment-ktx:1.3.0-alpha03',
|
||||
lifecycle_common: 'androidx.lifecycle:lifecycle-common-java8:2.3.0-alpha01',
|
||||
lifecycle_livedata_ktx: 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.0-alpha01',
|
||||
lifecycle_viewmodel_ktx: 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.0-alpha01',
|
||||
local_broadcast_manager: 'androidx.localbroadcastmanager:localbroadcastmanager:1.1.0-alpha01',
|
||||
|
Reference in New Issue
Block a user