Rewrite PasswordFragment in Kotlin
Signed-off-by: Harsh Shandilya <msfjarvis@gmail.com>
This commit is contained in:
parent
14d997f500
commit
8fc7dd3d42
2 changed files with 206 additions and 257 deletions
|
@ -1,257 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2014-2019 The Android Password Store Authors. All Rights Reserved.
|
||||
* SPDX-License-Identifier: GPL-3.0-only
|
||||
*/
|
||||
package com.zeapo.pwdstore;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.recyclerview.widget.DividerItemDecoration;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.zeapo.pwdstore.ui.adapters.PasswordRecyclerAdapter;
|
||||
import com.zeapo.pwdstore.utils.PasswordItem;
|
||||
import com.zeapo.pwdstore.utils.PasswordRepository;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
* A fragment representing a list of Items.
|
||||
*
|
||||
* <p>Large screen devices (such as tablets) are supported by replacing the ListView with a
|
||||
* GridView.
|
||||
*
|
||||
* <p>
|
||||
*/
|
||||
public class PasswordFragment extends Fragment {
|
||||
|
||||
// store the pass files list in a stack
|
||||
private Stack<ArrayList<PasswordItem>> passListStack;
|
||||
private Stack<File> pathStack;
|
||||
private Stack<Integer> scrollPosition;
|
||||
private PasswordRecyclerAdapter recyclerAdapter;
|
||||
private RecyclerView recyclerView;
|
||||
private OnFragmentInteractionListener mListener;
|
||||
private SharedPreferences settings;
|
||||
|
||||
/**
|
||||
* Mandatory empty constructor for the fragment manager to instantiate the fragment (e.g. upon
|
||||
* screen orientation changes).
|
||||
*/
|
||||
public PasswordFragment() {}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
String path = getArguments().getString("Path");
|
||||
|
||||
settings = PreferenceManager.getDefaultSharedPreferences(requireActivity());
|
||||
passListStack = new Stack<>();
|
||||
scrollPosition = new Stack<>();
|
||||
pathStack = new Stack<>();
|
||||
recyclerAdapter =
|
||||
new PasswordRecyclerAdapter(
|
||||
(PasswordStore) requireActivity(),
|
||||
mListener,
|
||||
PasswordRepository.getPasswords(
|
||||
new File(path),
|
||||
PasswordRepository.getRepositoryDirectory(requireContext()),
|
||||
getSortOrder()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(
|
||||
@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.password_recycler_view, container, false);
|
||||
|
||||
// use a linear layout manager
|
||||
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(requireContext());
|
||||
|
||||
recyclerView = view.findViewById(R.id.pass_recycler);
|
||||
recyclerView.setLayoutManager(mLayoutManager);
|
||||
|
||||
// use divider
|
||||
recyclerView.addItemDecoration(
|
||||
new DividerItemDecoration(requireContext(), DividerItemDecoration.VERTICAL));
|
||||
|
||||
// Set the adapter
|
||||
recyclerView.setAdapter(recyclerAdapter);
|
||||
|
||||
final FloatingActionButton fab = view.findViewById(R.id.fab);
|
||||
fab.setOnClickListener(v -> ((PasswordStore) requireActivity()).createPassword());
|
||||
|
||||
registerForContextMenu(recyclerView);
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(final Context context) {
|
||||
super.onAttach(context);
|
||||
try {
|
||||
mListener =
|
||||
item -> {
|
||||
if (item.getType() == PasswordItem.TYPE_CATEGORY) {
|
||||
// push the current password list (non filtered plz!)
|
||||
passListStack.push(
|
||||
pathStack.isEmpty()
|
||||
? PasswordRepository.getPasswords(
|
||||
PasswordRepository.getRepositoryDirectory(
|
||||
context),
|
||||
getSortOrder())
|
||||
: PasswordRepository.getPasswords(
|
||||
pathStack.peek(),
|
||||
PasswordRepository.getRepositoryDirectory(
|
||||
context),
|
||||
getSortOrder()));
|
||||
// push the category were we're going
|
||||
pathStack.push(item.getFile());
|
||||
scrollPosition.push(recyclerView.getVerticalScrollbarPosition());
|
||||
|
||||
recyclerView.scrollToPosition(0);
|
||||
recyclerAdapter.clear();
|
||||
recyclerAdapter.addAll(
|
||||
PasswordRepository.getPasswords(
|
||||
item.getFile(),
|
||||
PasswordRepository.getRepositoryDirectory(context),
|
||||
getSortOrder()));
|
||||
|
||||
((AppCompatActivity) requireActivity())
|
||||
.getSupportActionBar()
|
||||
.setDisplayHomeAsUpEnabled(true);
|
||||
} else {
|
||||
if (getArguments().getBoolean("matchWith", false)) {
|
||||
((PasswordStore) requireActivity()).matchPasswordWithApp(item);
|
||||
} else {
|
||||
((PasswordStore) requireActivity()).decryptPassword(item);
|
||||
}
|
||||
}
|
||||
};
|
||||
} catch (ClassCastException e) {
|
||||
throw new ClassCastException(context + " must implement OnFragmentInteractionListener");
|
||||
}
|
||||
}
|
||||
|
||||
/** clears the adapter content and sets it back to the root view */
|
||||
public void updateAdapter() {
|
||||
passListStack.clear();
|
||||
pathStack.clear();
|
||||
scrollPosition.clear();
|
||||
recyclerAdapter.clear();
|
||||
recyclerAdapter.addAll(
|
||||
PasswordRepository.getPasswords(
|
||||
PasswordRepository.getRepositoryDirectory(requireContext()),
|
||||
getSortOrder()));
|
||||
|
||||
((AppCompatActivity) requireActivity())
|
||||
.getSupportActionBar()
|
||||
.setDisplayHomeAsUpEnabled(false);
|
||||
}
|
||||
|
||||
/** refreshes the adapter with the latest opened category */
|
||||
public void refreshAdapter() {
|
||||
recyclerAdapter.clear();
|
||||
recyclerAdapter.addAll(
|
||||
pathStack.isEmpty()
|
||||
? PasswordRepository.getPasswords(
|
||||
PasswordRepository.getRepositoryDirectory(requireContext()),
|
||||
getSortOrder())
|
||||
: PasswordRepository.getPasswords(
|
||||
pathStack.peek(),
|
||||
PasswordRepository.getRepositoryDirectory(requireContext()),
|
||||
getSortOrder()));
|
||||
}
|
||||
|
||||
/**
|
||||
* filters the list adapter
|
||||
*
|
||||
* @param filter the filter to apply
|
||||
*/
|
||||
public void filterAdapter(String filter) {
|
||||
if (filter.isEmpty()) {
|
||||
refreshAdapter();
|
||||
} else {
|
||||
recursiveFilter(filter, pathStack.isEmpty() ? null : pathStack.peek());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* recursively filters a directory and extract all the matching items
|
||||
*
|
||||
* @param filter the filter to apply
|
||||
* @param dir the directory to filter
|
||||
*/
|
||||
private void recursiveFilter(String filter, File dir) {
|
||||
// on the root the pathStack is empty
|
||||
ArrayList<PasswordItem> passwordItems =
|
||||
dir == null
|
||||
? PasswordRepository.getPasswords(
|
||||
PasswordRepository.getRepositoryDirectory(requireContext()),
|
||||
getSortOrder())
|
||||
: PasswordRepository.getPasswords(
|
||||
dir,
|
||||
PasswordRepository.getRepositoryDirectory(requireContext()),
|
||||
getSortOrder());
|
||||
|
||||
boolean rec = settings.getBoolean("filter_recursively", true);
|
||||
for (PasswordItem item : passwordItems) {
|
||||
if (item.getType() == PasswordItem.TYPE_CATEGORY && rec) {
|
||||
recursiveFilter(filter, item.getFile());
|
||||
}
|
||||
boolean matches = item.toString().toLowerCase().contains(filter.toLowerCase());
|
||||
boolean inAdapter = recyclerAdapter.getValues().contains(item);
|
||||
if (matches && !inAdapter) {
|
||||
recyclerAdapter.add(item);
|
||||
} else if (!matches && inAdapter) {
|
||||
recyclerAdapter.remove(recyclerAdapter.getValues().indexOf(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Goes back one level back in the path */
|
||||
public void popBack() {
|
||||
if (passListStack.isEmpty()) return;
|
||||
|
||||
recyclerView.scrollToPosition(scrollPosition.pop());
|
||||
recyclerAdapter.clear();
|
||||
recyclerAdapter.addAll(passListStack.pop());
|
||||
pathStack.pop();
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the current directory
|
||||
*
|
||||
* @return the current directory
|
||||
*/
|
||||
public File getCurrentDir() {
|
||||
if (pathStack.isEmpty()) return PasswordRepository.getRepositoryDirectory(requireContext());
|
||||
else return pathStack.peek();
|
||||
}
|
||||
|
||||
public boolean isNotEmpty() {
|
||||
return !passListStack.isEmpty();
|
||||
}
|
||||
|
||||
public void dismissActionMode() {
|
||||
if (recyclerAdapter != null && recyclerAdapter.getActionMode() != null) {
|
||||
recyclerAdapter.getActionMode().finish();
|
||||
}
|
||||
}
|
||||
|
||||
private PasswordRepository.PasswordSortOrder getSortOrder() {
|
||||
return PasswordRepository.PasswordSortOrder.getSortOrder(settings);
|
||||
}
|
||||
|
||||
public interface OnFragmentInteractionListener {
|
||||
void onFragmentInteraction(PasswordItem item);
|
||||
}
|
||||
}
|
206
app/src/main/java/com/zeapo/pwdstore/PasswordFragment.kt
Normal file
206
app/src/main/java/com/zeapo/pwdstore/PasswordFragment.kt
Normal file
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
* Copyright © 2014-2019 The Android Password Store Authors. All Rights Reserved.
|
||||
* SPDX-License-Identifier: GPL-3.0-only
|
||||
*/
|
||||
package com.zeapo.pwdstore
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
import com.zeapo.pwdstore.ui.adapters.PasswordRecyclerAdapter
|
||||
import com.zeapo.pwdstore.utils.PasswordItem
|
||||
import com.zeapo.pwdstore.utils.PasswordRepository
|
||||
import com.zeapo.pwdstore.utils.PasswordRepository.Companion.getPasswords
|
||||
import com.zeapo.pwdstore.utils.PasswordRepository.Companion.getRepositoryDirectory
|
||||
import com.zeapo.pwdstore.utils.PasswordRepository.PasswordSortOrder.Companion.getSortOrder
|
||||
import java.io.File
|
||||
import java.util.Locale
|
||||
import java.util.Stack
|
||||
|
||||
/**
|
||||
* A fragment representing a list of Items.
|
||||
*
|
||||
*
|
||||
* Large screen devices (such as tablets) are supported by replacing the ListView with a
|
||||
* GridView.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
class PasswordFragment
|
||||
/**
|
||||
* Mandatory empty constructor for the fragment manager to instantiate the fragment (e.g. upon
|
||||
* screen orientation changes).
|
||||
*/
|
||||
: Fragment() {
|
||||
// store the pass files list in a stack
|
||||
private var passListStack: Stack<ArrayList<PasswordItem>> = Stack()
|
||||
private var pathStack: Stack<File> = Stack()
|
||||
private var scrollPosition: Stack<Int> = Stack()
|
||||
private lateinit var recyclerAdapter: PasswordRecyclerAdapter
|
||||
private lateinit var recyclerView: RecyclerView
|
||||
private lateinit var listener: OnFragmentInteractionListener
|
||||
private lateinit var settings: SharedPreferences
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
val path = requireNotNull(requireArguments().getString("Path"))
|
||||
settings = PreferenceManager.getDefaultSharedPreferences(requireActivity())
|
||||
recyclerAdapter = PasswordRecyclerAdapter((requireActivity() as PasswordStore),
|
||||
listener, getPasswords(File(path), getRepositoryDirectory(requireContext()), sortOrder))
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
val view = inflater.inflate(R.layout.password_recycler_view, container, false)
|
||||
// use a linear layout manager
|
||||
val layoutManager = LinearLayoutManager(requireContext())
|
||||
recyclerView = view.findViewById(R.id.pass_recycler)
|
||||
recyclerView.layoutManager = layoutManager
|
||||
// use divider
|
||||
recyclerView.addItemDecoration(DividerItemDecoration(requireContext(), DividerItemDecoration.VERTICAL))
|
||||
// Set the adapter
|
||||
recyclerView.adapter = recyclerAdapter
|
||||
val fab: FloatingActionButton = view.findViewById(R.id.fab)
|
||||
fab.setOnClickListener { (requireActivity() as PasswordStore).createPassword() }
|
||||
registerForContextMenu(recyclerView)
|
||||
return view
|
||||
}
|
||||
|
||||
override fun onAttach(context: Context) {
|
||||
super.onAttach(context)
|
||||
try {
|
||||
listener = object : OnFragmentInteractionListener {
|
||||
override fun onFragmentInteraction(item: PasswordItem) {
|
||||
if (item.type == PasswordItem.TYPE_CATEGORY) { // push the current password list (non filtered plz!)
|
||||
passListStack.push(
|
||||
if (pathStack.isEmpty())
|
||||
getPasswords(getRepositoryDirectory(context), sortOrder)
|
||||
else
|
||||
getPasswords(pathStack.peek(), getRepositoryDirectory(context), sortOrder)
|
||||
)
|
||||
// push the category were we're going
|
||||
pathStack.push(item.file)
|
||||
scrollPosition.push(recyclerView.verticalScrollbarPosition)
|
||||
recyclerView.scrollToPosition(0)
|
||||
recyclerAdapter.clear()
|
||||
recyclerAdapter.addAll(getPasswords(item.file, getRepositoryDirectory(context), sortOrder))
|
||||
(requireActivity() as AppCompatActivity).supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
} else {
|
||||
if (requireArguments().getBoolean("matchWith", false)) {
|
||||
(requireActivity() as PasswordStore).matchPasswordWithApp(item)
|
||||
} else {
|
||||
(requireActivity() as PasswordStore).decryptPassword(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: ClassCastException) {
|
||||
throw ClassCastException("$context must implement OnFragmentInteractionListener")
|
||||
}
|
||||
}
|
||||
|
||||
/** clears the adapter content and sets it back to the root view */
|
||||
fun updateAdapter() {
|
||||
passListStack.clear()
|
||||
pathStack.clear()
|
||||
scrollPosition.clear()
|
||||
recyclerAdapter.clear()
|
||||
recyclerAdapter.addAll(getPasswords(getRepositoryDirectory(requireContext()), sortOrder))
|
||||
(requireActivity() as AppCompatActivity).supportActionBar?.setDisplayHomeAsUpEnabled(false)
|
||||
}
|
||||
|
||||
/** refreshes the adapter with the latest opened category */
|
||||
fun refreshAdapter() {
|
||||
recyclerAdapter.clear()
|
||||
recyclerAdapter.addAll(
|
||||
if (pathStack.isEmpty())
|
||||
getPasswords(getRepositoryDirectory(requireContext()), sortOrder)
|
||||
else
|
||||
getPasswords(pathStack.peek(), getRepositoryDirectory(requireContext()), sortOrder)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* filters the list adapter
|
||||
*
|
||||
* @param filter the filter to apply
|
||||
*/
|
||||
fun filterAdapter(filter: String) {
|
||||
if (filter.isEmpty()) {
|
||||
refreshAdapter()
|
||||
} else {
|
||||
recursiveFilter(filter, if (pathStack.isEmpty()) null else pathStack.peek())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* recursively filters a directory and extract all the matching items
|
||||
*
|
||||
* @param filter the filter to apply
|
||||
* @param dir the directory to filter
|
||||
*/
|
||||
private fun recursiveFilter(filter: String, dir: File?) { // on the root the pathStack is empty
|
||||
val passwordItems = if (dir == null)
|
||||
getPasswords(getRepositoryDirectory(requireContext()), sortOrder)
|
||||
else
|
||||
getPasswords(dir, getRepositoryDirectory(requireContext()), sortOrder)
|
||||
val rec = settings.getBoolean("filter_recursively", true)
|
||||
for (item in passwordItems) {
|
||||
if (item.type == PasswordItem.TYPE_CATEGORY && rec) {
|
||||
recursiveFilter(filter, item.file)
|
||||
}
|
||||
val matches = item.toString().toLowerCase(Locale.ROOT).contains(filter.toLowerCase(Locale.ROOT))
|
||||
val inAdapter = recyclerAdapter.values.contains(item)
|
||||
if (matches && !inAdapter) {
|
||||
recyclerAdapter.add(item)
|
||||
} else if (!matches && inAdapter) {
|
||||
recyclerAdapter.remove(recyclerAdapter.values.indexOf(item))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Goes back one level back in the path */
|
||||
fun popBack() {
|
||||
if (passListStack.isEmpty()) return
|
||||
recyclerView.scrollToPosition(scrollPosition.pop())
|
||||
recyclerAdapter.clear()
|
||||
recyclerAdapter.addAll(passListStack.pop())
|
||||
pathStack.pop()
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the current directory
|
||||
*
|
||||
* @return the current directory
|
||||
*/
|
||||
val currentDir: File?
|
||||
get() = if (pathStack.isEmpty()) getRepositoryDirectory(requireContext()) else pathStack.peek()
|
||||
|
||||
val isNotEmpty: Boolean
|
||||
get() = !passListStack.isEmpty()
|
||||
|
||||
fun dismissActionMode() {
|
||||
recyclerAdapter.actionMode?.finish()
|
||||
}
|
||||
|
||||
private val sortOrder: PasswordRepository.PasswordSortOrder
|
||||
get() = getSortOrder(settings)
|
||||
|
||||
interface OnFragmentInteractionListener {
|
||||
fun onFragmentInteraction(item: PasswordItem)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue