mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Kotlinized fragments
This commit is contained in:
@@ -36,6 +36,7 @@ import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.activities.lock.LockingHideActivity
|
||||
import com.kunzisoft.keepass.activities.view.EntryContentsView
|
||||
import com.kunzisoft.keepass.app.App
|
||||
import com.kunzisoft.keepass.database.element.EntryVersioned
|
||||
import com.kunzisoft.keepass.database.element.PwNodeId
|
||||
@@ -48,7 +49,6 @@ import com.kunzisoft.keepass.timeout.ClipboardHelper
|
||||
import com.kunzisoft.keepass.timeout.TimeoutHelper
|
||||
import com.kunzisoft.keepass.utils.MenuUtil
|
||||
import com.kunzisoft.keepass.utils.Util
|
||||
import com.kunzisoft.keepass.view.EntryContentsView
|
||||
|
||||
class EntryActivity : LockingHideActivity() {
|
||||
|
||||
|
||||
@@ -29,38 +29,26 @@ import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.EditText
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.ScrollView
|
||||
import android.widget.Toast
|
||||
|
||||
import android.widget.*
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.activities.dialogs.GeneratePasswordDialogFragment
|
||||
import com.kunzisoft.keepass.activities.dialogs.IconPickerDialogFragment
|
||||
import com.kunzisoft.keepass.activities.dialogs.IconPickerDialogFragment.Companion.KEY_ICON_STANDARD
|
||||
import com.kunzisoft.keepass.activities.lock.LockingHideActivity
|
||||
import com.kunzisoft.keepass.activities.view.EntryEditCustomField
|
||||
import com.kunzisoft.keepass.app.App
|
||||
import com.kunzisoft.keepass.database.action.node.ActionNodeValues
|
||||
import com.kunzisoft.keepass.database.action.node.AddEntryRunnable
|
||||
import com.kunzisoft.keepass.database.action.node.AfterActionNodeFinishRunnable
|
||||
import com.kunzisoft.keepass.database.action.node.UpdateEntryRunnable
|
||||
import com.kunzisoft.keepass.database.element.Database
|
||||
import com.kunzisoft.keepass.database.element.EntryVersioned
|
||||
import com.kunzisoft.keepass.database.element.GroupVersioned
|
||||
import com.kunzisoft.keepass.database.element.PwDate
|
||||
import com.kunzisoft.keepass.database.element.PwIcon
|
||||
import com.kunzisoft.keepass.database.element.PwIconStandard
|
||||
import com.kunzisoft.keepass.database.element.PwNodeId
|
||||
import com.kunzisoft.keepass.database.element.*
|
||||
import com.kunzisoft.keepass.database.element.security.ProtectedString
|
||||
import com.kunzisoft.keepass.dialogs.GeneratePasswordDialogFragment
|
||||
import com.kunzisoft.keepass.dialogs.IconPickerDialogFragment
|
||||
import com.kunzisoft.keepass.education.EntryEditActivityEducation
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import com.kunzisoft.keepass.tasks.ActionRunnable
|
||||
import com.kunzisoft.keepass.timeout.TimeoutHelper
|
||||
import com.kunzisoft.keepass.utils.MenuUtil
|
||||
import com.kunzisoft.keepass.utils.Util
|
||||
import com.kunzisoft.keepass.view.EntryEditCustomField
|
||||
|
||||
import com.kunzisoft.keepass.dialogs.IconPickerDialogFragment.KEY_ICON_STANDARD
|
||||
|
||||
class EntryEditActivity : LockingHideActivity(), IconPickerDialogFragment.IconPickerListener, GeneratePasswordDialogFragment.GeneratePasswordListener {
|
||||
|
||||
|
||||
@@ -47,8 +47,8 @@ import com.kunzisoft.keepass.autofill.AutofillHelper
|
||||
import com.kunzisoft.keepass.database.action.AssignPasswordInDatabaseRunnable
|
||||
import com.kunzisoft.keepass.database.action.CreateDatabaseRunnable
|
||||
import com.kunzisoft.keepass.database.action.ProgressDialogRunnable
|
||||
import com.kunzisoft.keepass.dialogs.AssignMasterKeyDialogFragment
|
||||
import com.kunzisoft.keepass.dialogs.CreateFileDialogFragment
|
||||
import com.kunzisoft.keepass.activities.dialogs.AssignMasterKeyDialogFragment
|
||||
import com.kunzisoft.keepass.activities.dialogs.CreateFileDialogFragment
|
||||
import com.kunzisoft.keepass.education.FileDatabaseSelectActivityEducation
|
||||
import com.kunzisoft.keepass.fileselect.*
|
||||
import com.kunzisoft.keepass.fileselect.database.FileDatabaseHistory
|
||||
@@ -376,8 +376,10 @@ class FileDatabaseSelectActivity : StylishActivity(),
|
||||
|
||||
}
|
||||
|
||||
override fun onDefinePathDialogPositiveClick(pathFile: Uri): Boolean {
|
||||
override fun onDefinePathDialogPositiveClick(pathFile: Uri?): Boolean {
|
||||
mDatabaseFileUri = pathFile
|
||||
if (pathFile == null)
|
||||
return false
|
||||
return if (createDatabaseFile(pathFile)) {
|
||||
AssignMasterKeyDialogFragment().show(supportFragmentManager, "passwordDialog")
|
||||
true
|
||||
@@ -385,7 +387,7 @@ class FileDatabaseSelectActivity : StylishActivity(),
|
||||
false
|
||||
}
|
||||
|
||||
override fun onDefinePathDialogNegativeClick(pathFile: Uri): Boolean {
|
||||
override fun onDefinePathDialogNegativeClick(pathFile: Uri?): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.activities.lock.LockingActivity
|
||||
@@ -62,12 +63,12 @@ import com.kunzisoft.keepass.database.action.node.MoveEntryRunnable
|
||||
import com.kunzisoft.keepass.database.action.node.MoveGroupRunnable
|
||||
import com.kunzisoft.keepass.database.action.node.UpdateGroupRunnable
|
||||
import com.kunzisoft.keepass.database.element.*
|
||||
import com.kunzisoft.keepass.dialogs.AssignMasterKeyDialogFragment
|
||||
import com.kunzisoft.keepass.dialogs.GroupEditDialogFragment
|
||||
import com.kunzisoft.keepass.dialogs.IconPickerDialogFragment
|
||||
import com.kunzisoft.keepass.dialogs.PasswordEncodingDialogHelper
|
||||
import com.kunzisoft.keepass.dialogs.ReadOnlyDialog
|
||||
import com.kunzisoft.keepass.dialogs.SortDialogFragment
|
||||
import com.kunzisoft.keepass.activities.dialogs.AssignMasterKeyDialogFragment
|
||||
import com.kunzisoft.keepass.activities.dialogs.GroupEditDialogFragment
|
||||
import com.kunzisoft.keepass.activities.dialogs.IconPickerDialogFragment
|
||||
import com.kunzisoft.keepass.activities.dialogs.PasswordEncodingDialogHelper
|
||||
import com.kunzisoft.keepass.activities.dialogs.ReadOnlyDialog
|
||||
import com.kunzisoft.keepass.activities.dialogs.SortDialogFragment
|
||||
import com.kunzisoft.keepass.education.GroupActivityEducation
|
||||
import com.kunzisoft.keepass.magikeyboard.KeyboardEntryNotificationService
|
||||
import com.kunzisoft.keepass.magikeyboard.KeyboardHelper
|
||||
@@ -77,7 +78,7 @@ import com.kunzisoft.keepass.model.Field
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import com.kunzisoft.keepass.timeout.TimeoutHelper
|
||||
import com.kunzisoft.keepass.utils.MenuUtil
|
||||
import com.kunzisoft.keepass.view.AddNodeButtonView
|
||||
import com.kunzisoft.keepass.activities.view.AddNodeButtonView
|
||||
|
||||
import net.cachapa.expandablelayout.ExpandableLayout
|
||||
|
||||
@@ -774,17 +775,20 @@ class GroupActivity : LockingActivity(),
|
||||
AssignMasterKeyDialogFragment().show(supportFragmentManager, "passwordDialog")
|
||||
}
|
||||
|
||||
override fun approveEditGroup(action: GroupEditDialogFragment.EditGroupDialogAction,
|
||||
name: String,
|
||||
icon: PwIcon) {
|
||||
override fun approveEditGroup(action: GroupEditDialogFragment.EditGroupDialogAction?,
|
||||
name: String?,
|
||||
icon: PwIcon?) {
|
||||
val database = App.currentDatabase
|
||||
|
||||
if (name.isNullOrEmpty() || icon == null)
|
||||
Toast.makeText(this, R.string.error_no_name, Toast.LENGTH_LONG).show()
|
||||
else {
|
||||
when (action) {
|
||||
GroupEditDialogFragment.EditGroupDialogAction.CREATION -> {
|
||||
// If group creation
|
||||
mCurrentGroup?.let { currentGroup ->
|
||||
// Build the group
|
||||
database.createGroup()?.let { newGroup->
|
||||
database.createGroup()?.let { newGroup ->
|
||||
newGroup.title = name
|
||||
newGroup.icon = icon
|
||||
// Not really needed here because added in runnable but safe
|
||||
@@ -821,7 +825,9 @@ class GroupActivity : LockingActivity(),
|
||||
).start()
|
||||
}
|
||||
}
|
||||
else -> {}
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -874,9 +880,9 @@ class GroupActivity : LockingActivity(),
|
||||
}
|
||||
}
|
||||
|
||||
override fun cancelEditGroup(action: GroupEditDialogFragment.EditGroupDialogAction,
|
||||
name: String,
|
||||
iconId: PwIcon) {
|
||||
override fun cancelEditGroup(action: GroupEditDialogFragment.EditGroupDialogAction?,
|
||||
name: String?,
|
||||
iconId: PwIcon?) {
|
||||
// Do nothing here
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ import com.kunzisoft.keepass.adapters.NodeAdapter
|
||||
import com.kunzisoft.keepass.database.SortNodeEnum
|
||||
import com.kunzisoft.keepass.database.element.GroupVersioned
|
||||
import com.kunzisoft.keepass.database.element.NodeVersioned
|
||||
import com.kunzisoft.keepass.dialogs.SortDialogFragment
|
||||
import com.kunzisoft.keepass.activities.dialogs.SortDialogFragment
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import com.kunzisoft.keepass.activities.stylish.StylishFragment
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ import com.kunzisoft.keepass.autofill.AutofillHelper
|
||||
import com.kunzisoft.keepass.database.action.LoadDatabaseRunnable
|
||||
import com.kunzisoft.keepass.database.action.ProgressDialogRunnable
|
||||
import com.kunzisoft.keepass.database.element.Database
|
||||
import com.kunzisoft.keepass.dialogs.PasswordEncodingDialogHelper
|
||||
import com.kunzisoft.keepass.activities.dialogs.PasswordEncodingDialogHelper
|
||||
import com.kunzisoft.keepass.education.PasswordActivityEducation
|
||||
import com.kunzisoft.keepass.fileselect.KeyFileHelper
|
||||
import com.kunzisoft.keepass.fingerprint.FingerPrintAnimatedVector
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.dialogs
|
||||
package com.kunzisoft.keepass.activities.dialogs
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
@@ -57,7 +57,6 @@ class AssignMasterKeyDialogFragment : DialogFragment() {
|
||||
interface AssignPasswordDialogListener {
|
||||
fun onAssignKeyDialogPositiveClick(masterPasswordChecked: Boolean, masterPassword: String?,
|
||||
keyFileChecked: Boolean, keyFile: Uri?)
|
||||
|
||||
fun onAssignKeyDialogNegativeClick(masterPasswordChecked: Boolean, masterPassword: String?,
|
||||
keyFileChecked: Boolean, keyFile: Uri?)
|
||||
}
|
||||
@@ -74,10 +73,9 @@ class AssignMasterKeyDialogFragment : DialogFragment() {
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
|
||||
activity?.let { notNullActivity ->
|
||||
val builder = AlertDialog.Builder(notNullActivity)
|
||||
val inflater = notNullActivity.layoutInflater
|
||||
activity?.let { activity ->
|
||||
val builder = AlertDialog.Builder(activity)
|
||||
val inflater = activity.layoutInflater
|
||||
|
||||
rootView = inflater.inflate(R.layout.set_password, null)
|
||||
builder.setView(rootView)
|
||||
@@ -126,14 +124,12 @@ class AssignMasterKeyDialogFragment : DialogFragment() {
|
||||
mKeyFile = null
|
||||
|
||||
var error = verifyPassword() || verifyFile()
|
||||
|
||||
if (!passwordCheckBox!!.isChecked && !keyFileCheckBox!!.isChecked) {
|
||||
error = true
|
||||
showNoKeyConfirmationDialog()
|
||||
}
|
||||
|
||||
if (!error) {
|
||||
mListener!!.onAssignKeyDialogPositiveClick(
|
||||
mListener?.onAssignKeyDialogPositiveClick(
|
||||
passwordCheckBox!!.isChecked, mMasterPassword,
|
||||
keyFileCheckBox!!.isChecked, mKeyFile)
|
||||
dismiss()
|
||||
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright 2019 Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* KeePass DX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.activities.dialogs
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.support.v4.app.DialogFragment
|
||||
import android.support.v7.app.AlertDialog
|
||||
import android.view.ActionMode
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.AdapterView
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.Button
|
||||
import android.widget.EditText
|
||||
import android.widget.Spinner
|
||||
import android.widget.TextView
|
||||
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.activities.stylish.FilePickerStylishActivity
|
||||
import com.kunzisoft.keepass.utils.UriUtil
|
||||
import com.nononsenseapps.filepicker.FilePickerActivity
|
||||
import com.nononsenseapps.filepicker.Utils
|
||||
|
||||
class CreateFileDialogFragment : DialogFragment(), AdapterView.OnItemSelectedListener {
|
||||
|
||||
private val FILE_CODE = 3853
|
||||
|
||||
private var folderPathView: EditText? = null
|
||||
private var fileNameView: EditText? = null
|
||||
private var positiveButton: Button? = null
|
||||
private var negativeButton: Button? = null
|
||||
|
||||
private var mDefinePathDialogListener: DefinePathDialogListener? = null
|
||||
|
||||
private var mDatabaseFileExtension: String? = null
|
||||
private var mUriPath: Uri? = null
|
||||
|
||||
interface DefinePathDialogListener {
|
||||
fun onDefinePathDialogPositiveClick(pathFile: Uri?): Boolean
|
||||
fun onDefinePathDialogNegativeClick(pathFile: Uri?): Boolean
|
||||
}
|
||||
|
||||
override fun onAttach(activity: Context?) {
|
||||
super.onAttach(activity)
|
||||
try {
|
||||
mDefinePathDialogListener = activity as DefinePathDialogListener?
|
||||
} catch (e: ClassCastException) {
|
||||
throw ClassCastException(activity?.toString()
|
||||
+ " must implement " + DefinePathDialogListener::class.java.name)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
activity?.let { activity ->
|
||||
val builder = AlertDialog.Builder(activity)
|
||||
val inflater = activity.layoutInflater
|
||||
|
||||
val rootView = inflater.inflate(R.layout.file_creation, null)
|
||||
builder.setView(rootView)
|
||||
.setTitle(R.string.create_keepass_file)
|
||||
// Add action buttons
|
||||
.setPositiveButton(android.R.string.ok) { _, _ -> }
|
||||
.setNegativeButton(R.string.cancel) { _, _ -> }
|
||||
|
||||
// To prevent crash issue #69 https://github.com/Kunzisoft/KeePassDX/issues/69
|
||||
val actionCopyBarCallback = object : ActionMode.Callback {
|
||||
|
||||
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
|
||||
positiveButton?.isEnabled = false
|
||||
negativeButton?.isEnabled = false
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onDestroyActionMode(mode: ActionMode) {
|
||||
positiveButton?.isEnabled = true
|
||||
negativeButton?.isEnabled = true
|
||||
}
|
||||
|
||||
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Folder selection
|
||||
val browseView = rootView.findViewById<View>(R.id.browse_button)
|
||||
folderPathView = rootView.findViewById(R.id.folder_path)
|
||||
folderPathView?.customSelectionActionModeCallback = actionCopyBarCallback
|
||||
fileNameView = rootView.findViewById(R.id.filename)
|
||||
fileNameView?.customSelectionActionModeCallback = actionCopyBarCallback
|
||||
|
||||
val defaultPath = Environment.getExternalStorageDirectory().path + getString(R.string.database_file_path_default)
|
||||
folderPathView?.setText(defaultPath)
|
||||
browseView.setOnClickListener { _ ->
|
||||
Intent(context, FilePickerStylishActivity::class.java).apply {
|
||||
putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false)
|
||||
putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, true)
|
||||
putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_DIR)
|
||||
putExtra(FilePickerActivity.EXTRA_START_PATH,
|
||||
Environment.getExternalStorageDirectory().path)
|
||||
startActivityForResult(this, FILE_CODE)
|
||||
}
|
||||
}
|
||||
|
||||
// Init path
|
||||
mUriPath = null
|
||||
|
||||
// Extension
|
||||
mDatabaseFileExtension = getString(R.string.database_file_extension_default)
|
||||
val spinner = rootView.findViewById<Spinner>(R.id.file_types)
|
||||
spinner.onItemSelectedListener = this
|
||||
|
||||
// Spinner Drop down elements
|
||||
val fileTypes = resources.getStringArray(R.array.file_types)
|
||||
val dataAdapter = ArrayAdapter(activity!!, android.R.layout.simple_spinner_item, fileTypes)
|
||||
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
||||
spinner.adapter = dataAdapter
|
||||
// Or text if only one item https://github.com/Kunzisoft/KeePassDX/issues/105
|
||||
if (fileTypes.size == 1) {
|
||||
val params = spinner.layoutParams
|
||||
spinner.visibility = View.GONE
|
||||
val extensionTextView = TextView(context)
|
||||
extensionTextView.text = mDatabaseFileExtension
|
||||
extensionTextView.layoutParams = params
|
||||
val parentView = spinner.parent as ViewGroup
|
||||
parentView.addView(extensionTextView)
|
||||
}
|
||||
|
||||
val dialog = builder.create()
|
||||
|
||||
dialog.setOnShowListener { dialog1 ->
|
||||
positiveButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE)
|
||||
negativeButton = dialog.getButton(DialogInterface.BUTTON_NEGATIVE)
|
||||
positiveButton?.setOnClickListener { _ ->
|
||||
mDefinePathDialogListener?.let {
|
||||
if (it.onDefinePathDialogPositiveClick(buildPath()))
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
negativeButton?.setOnClickListener { _->
|
||||
mDefinePathDialogListener?.let {
|
||||
if (it.onDefinePathDialogNegativeClick(buildPath())) {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return dialog
|
||||
}
|
||||
return super.onCreateDialog(savedInstanceState)
|
||||
}
|
||||
|
||||
private fun buildPath(): Uri? {
|
||||
if (folderPathView != null && mDatabaseFileExtension != null) {
|
||||
var path = Uri.Builder().path(folderPathView!!.text.toString())
|
||||
.appendPath(fileNameView!!.text.toString() + mDatabaseFileExtension!!)
|
||||
.build()
|
||||
path = UriUtil.translate(context, path)
|
||||
return path
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (requestCode == FILE_CODE && resultCode == Activity.RESULT_OK) {
|
||||
mUriPath = data?.data
|
||||
mUriPath?.let {
|
||||
val file = Utils.getFileForUri(it)
|
||||
folderPathView?.setText(file.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onItemSelected(adapterView: AdapterView<*>, view: View, position: Int, id: Long) {
|
||||
mDatabaseFileExtension = adapterView.getItemAtPosition(position).toString()
|
||||
}
|
||||
|
||||
override fun onNothingSelected(adapterView: AdapterView<*>) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright 2019 Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* KeePass DX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.activities.dialogs
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.DialogFragment
|
||||
import android.support.v7.app.AlertDialog
|
||||
import android.view.View
|
||||
import android.widget.*
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.password.PasswordGenerator
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import com.kunzisoft.keepass.utils.Util
|
||||
|
||||
class GeneratePasswordDialogFragment : DialogFragment() {
|
||||
|
||||
private var mListener: GeneratePasswordListener? = null
|
||||
|
||||
private var root: View? = null
|
||||
private var lengthTextView: EditText? = null
|
||||
private var passwordView: EditText? = null
|
||||
|
||||
private var uppercaseBox: CompoundButton? = null
|
||||
private var lowercaseBox: CompoundButton? = null
|
||||
private var digitsBox: CompoundButton? = null
|
||||
private var minusBox: CompoundButton? = null
|
||||
private var underlineBox: CompoundButton? = null
|
||||
private var spaceBox: CompoundButton? = null
|
||||
private var specialsBox: CompoundButton? = null
|
||||
private var bracketsBox: CompoundButton? = null
|
||||
private var extendedBox: CompoundButton? = null
|
||||
|
||||
override fun onAttach(context: Context?) {
|
||||
super.onAttach(context)
|
||||
try {
|
||||
mListener = context as GeneratePasswordListener?
|
||||
} catch (e: ClassCastException) {
|
||||
throw ClassCastException(context?.toString()
|
||||
+ " must implement " + GeneratePasswordListener::class.java.name)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
activity?.let { activity ->
|
||||
val builder = AlertDialog.Builder(activity)
|
||||
val inflater = activity.layoutInflater
|
||||
root = inflater.inflate(R.layout.generate_password, null)
|
||||
|
||||
passwordView = root?.findViewById(R.id.password)
|
||||
Util.applyFontVisibilityTo(context, passwordView)
|
||||
|
||||
lengthTextView = root?.findViewById(R.id.length)
|
||||
|
||||
uppercaseBox = root?.findViewById(R.id.cb_uppercase)
|
||||
lowercaseBox = root?.findViewById(R.id.cb_lowercase)
|
||||
digitsBox = root?.findViewById(R.id.cb_digits)
|
||||
minusBox = root?.findViewById(R.id.cb_minus)
|
||||
underlineBox = root?.findViewById(R.id.cb_underline)
|
||||
spaceBox = root?.findViewById(R.id.cb_space)
|
||||
specialsBox = root?.findViewById(R.id.cb_specials)
|
||||
bracketsBox = root?.findViewById(R.id.cb_brackets)
|
||||
extendedBox = root?.findViewById(R.id.cb_extended)
|
||||
|
||||
assignDefaultCharacters()
|
||||
|
||||
val seekBar = root?.findViewById<SeekBar>(R.id.seekbar_length)
|
||||
seekBar?.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
|
||||
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
|
||||
lengthTextView?.setText(progress.toString())
|
||||
}
|
||||
|
||||
override fun onStartTrackingTouch(seekBar: SeekBar) {}
|
||||
|
||||
override fun onStopTrackingTouch(seekBar: SeekBar) {}
|
||||
})
|
||||
seekBar?.progress = PreferencesUtil.getDefaultPasswordLength(context)
|
||||
|
||||
root?.findViewById<Button>(R.id.generate_password_button)
|
||||
?.setOnClickListener { fillPassword() }
|
||||
|
||||
builder.setView(root)
|
||||
.setPositiveButton(R.string.accept) { _, _ ->
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_PASSWORD_ID, passwordView!!.text.toString())
|
||||
mListener?.acceptPassword(bundle)
|
||||
|
||||
dismiss()
|
||||
}
|
||||
.setNegativeButton(R.string.cancel) { _, _ ->
|
||||
val bundle = Bundle()
|
||||
mListener?.cancelPassword(bundle)
|
||||
|
||||
dismiss()
|
||||
}
|
||||
|
||||
// Pre-populate a password to possibly save the user a few clicks
|
||||
fillPassword()
|
||||
|
||||
return builder.create()
|
||||
}
|
||||
return super.onCreateDialog(savedInstanceState)
|
||||
}
|
||||
|
||||
private fun assignDefaultCharacters() {
|
||||
uppercaseBox?.isChecked = false
|
||||
lowercaseBox?.isChecked = false
|
||||
digitsBox?.isChecked = false
|
||||
minusBox?.isChecked = false
|
||||
underlineBox?.isChecked = false
|
||||
spaceBox?.isChecked = false
|
||||
specialsBox?.isChecked = false
|
||||
bracketsBox?.isChecked = false
|
||||
extendedBox?.isChecked = false
|
||||
|
||||
val defaultPasswordChars = PreferencesUtil.getDefaultPasswordCharacters(context)
|
||||
for (passwordChar in defaultPasswordChars) {
|
||||
when (passwordChar) {
|
||||
getString(R.string.value_password_uppercase) -> uppercaseBox?.isChecked = true
|
||||
getString(R.string.value_password_lowercase) -> lowercaseBox?.isChecked = true
|
||||
getString(R.string.value_password_digits) -> digitsBox?.isChecked = true
|
||||
getString(R.string.value_password_minus) -> minusBox?.isChecked = true
|
||||
getString(R.string.value_password_underline) -> underlineBox?.isChecked = true
|
||||
getString(R.string.value_password_space) -> spaceBox?.isChecked = true
|
||||
getString(R.string.value_password_special) -> specialsBox?.isChecked = true
|
||||
getString(R.string.value_password_brackets) -> bracketsBox?.isChecked = true
|
||||
getString(R.string.value_password_extended) -> extendedBox?.isChecked = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun fillPassword() {
|
||||
root?.findViewById<EditText>(R.id.password)?.setText(generatePassword())
|
||||
}
|
||||
|
||||
fun generatePassword(): String {
|
||||
var password = ""
|
||||
try {
|
||||
val length = Integer.valueOf(root?.findViewById<EditText>(R.id.length)?.text.toString())
|
||||
|
||||
val generator = PasswordGenerator(activity)
|
||||
password = generator.generatePassword(length,
|
||||
uppercaseBox?.isChecked == true,
|
||||
lowercaseBox?.isChecked == true,
|
||||
digitsBox?.isChecked == true,
|
||||
minusBox?.isChecked == true,
|
||||
underlineBox?.isChecked == true,
|
||||
spaceBox?.isChecked == true,
|
||||
specialsBox?.isChecked == true,
|
||||
bracketsBox?.isChecked == true,
|
||||
extendedBox?.isChecked == true)
|
||||
} catch (e: NumberFormatException) {
|
||||
Toast.makeText(context, R.string.error_wrong_length, Toast.LENGTH_LONG).show()
|
||||
} catch (e: IllegalArgumentException) {
|
||||
Toast.makeText(context, e.message, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
return password
|
||||
}
|
||||
|
||||
interface GeneratePasswordListener {
|
||||
fun acceptPassword(bundle: Bundle)
|
||||
fun cancelPassword(bundle: Bundle)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val KEY_PASSWORD_ID = "KEY_PASSWORD_ID"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Copyright 2019 Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* KeePass DX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.activities.dialogs
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.DialogFragment
|
||||
import android.support.v7.app.AlertDialog
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.activities.dialogs.GroupEditDialogFragment.EditGroupDialogAction.CREATION
|
||||
import com.kunzisoft.keepass.activities.dialogs.GroupEditDialogFragment.EditGroupDialogAction.UPDATE
|
||||
import com.kunzisoft.keepass.app.App
|
||||
import com.kunzisoft.keepass.database.element.Database
|
||||
import com.kunzisoft.keepass.database.element.GroupVersioned
|
||||
import com.kunzisoft.keepass.database.element.PwIcon
|
||||
|
||||
class GroupEditDialogFragment : DialogFragment(), IconPickerDialogFragment.IconPickerListener {
|
||||
|
||||
private var mDatabase: Database? = null
|
||||
|
||||
private var editGroupListener: EditGroupListener? = null
|
||||
|
||||
private var editGroupDialogAction: EditGroupDialogAction? = null
|
||||
private var nameGroup: String? = null
|
||||
private var iconGroup: PwIcon? = null
|
||||
|
||||
private var iconButton: ImageView? = null
|
||||
private var iconColor: Int = 0
|
||||
|
||||
enum class EditGroupDialogAction {
|
||||
CREATION, UPDATE, NONE;
|
||||
|
||||
companion object {
|
||||
fun getActionFromOrdinal(ordinal: Int): EditGroupDialogAction {
|
||||
return values()[ordinal]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAttach(context: Context?) {
|
||||
super.onAttach(context)
|
||||
// Verify that the host activity implements the callback interface
|
||||
try {
|
||||
// Instantiate the NoticeDialogListener so we can send events to the host
|
||||
editGroupListener = context as EditGroupListener?
|
||||
} catch (e: ClassCastException) {
|
||||
// The activity doesn't implement the interface, throw exception
|
||||
throw ClassCastException(context?.toString()
|
||||
+ " must implement " + GroupEditDialogFragment::class.java.name)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
activity?.let { activity ->
|
||||
val root = activity.layoutInflater.inflate(R.layout.group_edit, null)
|
||||
val nameField = root?.findViewById<TextView>(R.id.group_edit_name)
|
||||
iconButton = root?.findViewById(R.id.group_edit_icon_button)
|
||||
|
||||
// Retrieve the textColor to tint the icon
|
||||
val ta = activity.theme.obtainStyledAttributes(intArrayOf(android.R.attr.textColorPrimary))
|
||||
iconColor = ta.getColor(0, Color.WHITE)
|
||||
ta.recycle()
|
||||
|
||||
// Init elements
|
||||
mDatabase = App.currentDatabase
|
||||
editGroupDialogAction = EditGroupDialogAction.NONE
|
||||
nameGroup = ""
|
||||
iconGroup = mDatabase?.iconFactory?.folderIcon
|
||||
|
||||
if (savedInstanceState != null
|
||||
&& savedInstanceState.containsKey(KEY_ACTION_ID)
|
||||
&& savedInstanceState.containsKey(KEY_NAME)
|
||||
&& savedInstanceState.containsKey(KEY_ICON)) {
|
||||
editGroupDialogAction = EditGroupDialogAction.getActionFromOrdinal(savedInstanceState.getInt(KEY_ACTION_ID))
|
||||
nameGroup = savedInstanceState.getString(KEY_NAME)
|
||||
iconGroup = savedInstanceState.getParcelable(KEY_ICON)
|
||||
|
||||
} else {
|
||||
arguments?.apply {
|
||||
if (containsKey(KEY_ACTION_ID))
|
||||
editGroupDialogAction = EditGroupDialogAction.getActionFromOrdinal(getInt(KEY_ACTION_ID))
|
||||
|
||||
if (containsKey(KEY_NAME) && containsKey(KEY_ICON)) {
|
||||
nameGroup = getString(KEY_NAME)
|
||||
iconGroup = getParcelable(KEY_ICON)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// populate the name
|
||||
nameField?.text = nameGroup
|
||||
// populate the icon
|
||||
assignIconView()
|
||||
|
||||
val builder = AlertDialog.Builder(activity)
|
||||
builder.setView(root)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
editGroupListener?.approveEditGroup(
|
||||
editGroupDialogAction,
|
||||
nameField?.text.toString(),
|
||||
iconGroup)
|
||||
|
||||
this@GroupEditDialogFragment.dialog.cancel()
|
||||
}
|
||||
.setNegativeButton(R.string.cancel) { _, _ ->
|
||||
editGroupListener?.cancelEditGroup(
|
||||
editGroupDialogAction,
|
||||
nameField?.text.toString(),
|
||||
iconGroup)
|
||||
|
||||
this@GroupEditDialogFragment.dialog.cancel()
|
||||
}
|
||||
|
||||
iconButton?.setOnClickListener { _ ->
|
||||
fragmentManager?.let {
|
||||
IconPickerDialogFragment().show(it, "IconPickerDialogFragment")
|
||||
}
|
||||
}
|
||||
|
||||
return builder.create()
|
||||
}
|
||||
return super.onCreateDialog(savedInstanceState)
|
||||
}
|
||||
|
||||
private fun assignIconView() {
|
||||
mDatabase?.drawFactory
|
||||
?.assignDatabaseIconTo(
|
||||
context,
|
||||
iconButton,
|
||||
iconGroup,
|
||||
iconColor)
|
||||
}
|
||||
|
||||
override fun iconPicked(bundle: Bundle) {
|
||||
iconGroup = bundle.getParcelable(IconPickerDialogFragment.KEY_ICON_STANDARD)
|
||||
assignIconView()
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
outState.putInt(KEY_ACTION_ID, editGroupDialogAction!!.ordinal)
|
||||
outState.putString(KEY_NAME, nameGroup)
|
||||
outState.putParcelable(KEY_ICON, iconGroup)
|
||||
super.onSaveInstanceState(outState)
|
||||
}
|
||||
|
||||
interface EditGroupListener {
|
||||
fun approveEditGroup(action: EditGroupDialogAction?, name: String?, icon: PwIcon?)
|
||||
fun cancelEditGroup(action: EditGroupDialogAction?, name: String?, icon: PwIcon?)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val TAG_CREATE_GROUP = "TAG_CREATE_GROUP"
|
||||
|
||||
const val KEY_NAME = "KEY_NAME"
|
||||
const val KEY_ICON = "KEY_ICON"
|
||||
const val KEY_ACTION_ID = "KEY_ACTION_ID"
|
||||
|
||||
fun build(): GroupEditDialogFragment {
|
||||
val bundle = Bundle()
|
||||
bundle.putInt(KEY_ACTION_ID, CREATION.ordinal)
|
||||
val fragment = GroupEditDialogFragment()
|
||||
fragment.arguments = bundle
|
||||
return fragment
|
||||
}
|
||||
|
||||
fun build(group: GroupVersioned): GroupEditDialogFragment {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_NAME, group.title)
|
||||
bundle.putParcelable(KEY_ICON, group.icon)
|
||||
bundle.putInt(KEY_ACTION_ID, UPDATE.ordinal)
|
||||
val fragment = GroupEditDialogFragment()
|
||||
fragment.arguments = bundle
|
||||
return fragment
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright 2019 Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* KeePass DX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.activities.dialogs
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.DialogFragment
|
||||
import android.support.v4.widget.ImageViewCompat
|
||||
import android.support.v7.app.AlertDialog
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.BaseAdapter
|
||||
import android.widget.GridView
|
||||
import android.widget.ImageView
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.activities.stylish.StylishActivity
|
||||
import com.kunzisoft.keepass.database.element.PwIconStandard
|
||||
import com.kunzisoft.keepass.icons.IconPack
|
||||
import com.kunzisoft.keepass.icons.IconPackChooser
|
||||
|
||||
|
||||
class IconPickerDialogFragment : DialogFragment() {
|
||||
|
||||
private var iconPickerListener: IconPickerListener? = null
|
||||
private var iconPack: IconPack? = null
|
||||
|
||||
override fun onAttach(context: Context?) {
|
||||
super.onAttach(context)
|
||||
try {
|
||||
iconPickerListener = context as IconPickerListener?
|
||||
} catch (e: ClassCastException) {
|
||||
// The activity doesn't implement the interface, throw exception
|
||||
throw ClassCastException(context!!.toString()
|
||||
+ " must implement " + IconPickerListener::class.java.name)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
activity?.let { activity ->
|
||||
val builder = AlertDialog.Builder(activity)
|
||||
|
||||
iconPack = IconPackChooser.getSelectedIconPack(context)
|
||||
|
||||
// Inflate and set the layout for the dialog
|
||||
// Pass null as the parent view because its going in the dialog layout
|
||||
val root = activity.layoutInflater.inflate(R.layout.icon_picker, null)
|
||||
builder.setView(root)
|
||||
|
||||
val currIconGridView = root.findViewById<GridView>(R.id.IconGridView)
|
||||
currIconGridView.adapter = ImageAdapter(activity)
|
||||
|
||||
currIconGridView.setOnItemClickListener { _, _, position, _ ->
|
||||
val bundle = Bundle()
|
||||
bundle.putParcelable(KEY_ICON_STANDARD, PwIconStandard(position))
|
||||
iconPickerListener?.iconPicked(bundle)
|
||||
dismiss()
|
||||
}
|
||||
|
||||
builder.setNegativeButton(R.string.cancel) { _, _ -> this@IconPickerDialogFragment.dialog.cancel() }
|
||||
|
||||
return builder.create()
|
||||
}
|
||||
return super.onCreateDialog(savedInstanceState)
|
||||
}
|
||||
|
||||
inner class ImageAdapter internal constructor(private val context: Context) : BaseAdapter() {
|
||||
|
||||
override fun getCount(): Int {
|
||||
return iconPack?.numberOfIcons() ?: 0
|
||||
}
|
||||
|
||||
override fun getItem(position: Int): Any? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun getItemId(position: Int): Long {
|
||||
return 0
|
||||
}
|
||||
|
||||
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
|
||||
val currentView: View = convertView
|
||||
?: (context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater)
|
||||
.inflate(R.layout.icon, parent, false)
|
||||
|
||||
iconPack?.let { iconPack ->
|
||||
val iconImageView = currentView.findViewById<ImageView>(R.id.icon_image)
|
||||
iconImageView.setImageResource(iconPack.iconToResId(position))
|
||||
|
||||
// Assign color if icons are tintable
|
||||
if (iconPack.tintable()) {
|
||||
// Retrieve the textColor to tint the icon
|
||||
val ta = context.theme.obtainStyledAttributes(intArrayOf(android.R.attr.textColor))
|
||||
ImageViewCompat.setImageTintList(iconImageView, ColorStateList.valueOf(ta.getColor(0, Color.BLACK)))
|
||||
ta?.recycle()
|
||||
}
|
||||
}
|
||||
|
||||
return currentView
|
||||
}
|
||||
}
|
||||
|
||||
interface IconPickerListener {
|
||||
fun iconPicked(bundle: Bundle)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val KEY_ICON_STANDARD = "KEY_ICON_STANDARD"
|
||||
|
||||
fun launch(activity: StylishActivity) {
|
||||
// Create an instance of the dialog fragment and show it
|
||||
val dialog = IconPickerDialogFragment()
|
||||
dialog.show(activity.supportFragmentManager, "IconPickerDialogFragment")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2019 Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* KeePass DX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.activities.dialogs
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Intent
|
||||
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
import android.os.Bundle
|
||||
import android.provider.Settings
|
||||
import android.support.v4.app.DialogFragment
|
||||
import android.support.v7.app.AlertDialog
|
||||
import android.view.View
|
||||
import com.kunzisoft.keepass.BuildConfig
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.utils.Util
|
||||
|
||||
class KeyboardExplanationDialogFragment : DialogFragment() {
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
activity?.let {
|
||||
val builder = AlertDialog.Builder(activity!!)
|
||||
val inflater = activity!!.layoutInflater
|
||||
|
||||
val rootView = inflater.inflate(R.layout.keyboard_explanation, null)
|
||||
|
||||
rootView.findViewById<View>(R.id.keyboards_activate_setting_path1_text)
|
||||
.setOnClickListener { launchActivateKeyboardSetting() }
|
||||
rootView.findViewById<View>(R.id.keyboards_activate_setting_path2_text)
|
||||
.setOnClickListener { launchActivateKeyboardSetting() }
|
||||
|
||||
val containerKeyboardSwitcher = rootView.findViewById<View>(R.id.container_keyboard_switcher)
|
||||
if (BuildConfig.CLOSED_STORE) {
|
||||
containerKeyboardSwitcher.setOnClickListener { Util.gotoUrl(context, R.string.keyboard_switcher_play_store) }
|
||||
} else {
|
||||
containerKeyboardSwitcher.setOnClickListener { Util.gotoUrl(context, R.string.keyboard_switcher_f_droid) }
|
||||
}
|
||||
|
||||
builder.setView(rootView)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ -> }
|
||||
return builder.create()
|
||||
}
|
||||
return super.onCreateDialog(savedInstanceState)
|
||||
}
|
||||
|
||||
private fun launchActivateKeyboardSetting() {
|
||||
val intent = Intent(Settings.ACTION_INPUT_METHOD_SETTINGS)
|
||||
intent.addFlags(FLAG_ACTIVITY_NEW_TASK)
|
||||
startActivity(intent)
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.dialogs
|
||||
package com.kunzisoft.keepass.activities.dialogs
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.content.Context
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2019 Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* KeePass DX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.activities.dialogs
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.DialogFragment
|
||||
import android.support.v7.app.AlertDialog
|
||||
import android.text.Html
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.widget.Toast
|
||||
|
||||
import com.kunzisoft.keepass.BuildConfig
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.utils.Util
|
||||
|
||||
/**
|
||||
* Custom Dialog that asks the user to download the pro version or make a donation.
|
||||
*/
|
||||
class ProFeatureDialogFragment : DialogFragment() {
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
activity?.let { activity ->
|
||||
// Use the Builder class for convenient dialog construction
|
||||
val builder = AlertDialog.Builder(activity)
|
||||
|
||||
val stringBuilder = SpannableStringBuilder()
|
||||
if (BuildConfig.CLOSED_STORE) {
|
||||
// TODO HtmlCompat with androidX
|
||||
stringBuilder.append(Html.fromHtml(getString(R.string.html_text_ad_free))).append("\n\n")
|
||||
stringBuilder.append(Html.fromHtml(getString(R.string.html_text_buy_pro)))
|
||||
builder.setPositiveButton(R.string.download) { _, _ ->
|
||||
try {
|
||||
Util.gotoUrl(context, R.string.app_pro_url)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
Toast.makeText(context, R.string.error_failed_to_launch_link, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
stringBuilder.append(Html.fromHtml(getString(R.string.html_text_feature_generosity))).append("\n\n")
|
||||
stringBuilder.append(Html.fromHtml(getString(R.string.html_text_donation)))
|
||||
builder.setPositiveButton(R.string.contribute) { _, _ ->
|
||||
try {
|
||||
Util.gotoUrl(context, R.string.contribution_url)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
Toast.makeText(context, R.string.error_failed_to_launch_link, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
builder.setMessage(stringBuilder)
|
||||
builder.setNegativeButton(android.R.string.cancel) { _, _ -> dismiss() }
|
||||
// Create the AlertDialog object and return it
|
||||
return builder.create()
|
||||
}
|
||||
return super.onCreateDialog(savedInstanceState)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2019 Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* KeePass DX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.activities.dialogs
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.preference.PreferenceManager
|
||||
|
||||
import com.kunzisoft.keepass.R
|
||||
|
||||
class ReadOnlyDialog(context: Context) : AlertDialog(context) {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle) {
|
||||
val ctx = context
|
||||
var warning = ctx.getString(R.string.read_only_warning)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
warning = warning + "\n\n" + context.getString(R.string.read_only_kitkat_warning)
|
||||
}
|
||||
setMessage(warning)
|
||||
|
||||
setButton(BUTTON_POSITIVE, ctx.getText(android.R.string.ok)) { _, _ -> dismiss() }
|
||||
setButton(BUTTON_NEGATIVE, ctx.getText(R.string.beta_dontask)) { _, _ ->
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(ctx)
|
||||
val edit = prefs.edit()
|
||||
edit.putBoolean(ctx.getString(R.string.show_read_only_warning), false)
|
||||
edit.apply()
|
||||
dismiss()
|
||||
}
|
||||
|
||||
super.onCreate(savedInstanceState)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Copyright 2019 Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* KeePass DX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.activities.dialogs
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.support.annotation.IdRes
|
||||
import android.support.v4.app.DialogFragment
|
||||
import android.support.v7.app.AlertDialog
|
||||
import android.view.View
|
||||
import android.widget.CompoundButton
|
||||
import android.widget.RadioGroup
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.database.SortNodeEnum
|
||||
|
||||
class SortDialogFragment : DialogFragment() {
|
||||
|
||||
private var mListener: SortSelectionListener? = null
|
||||
|
||||
private var mSortNodeEnum: SortNodeEnum? = null
|
||||
@IdRes
|
||||
private var mCheckedId: Int = 0
|
||||
private var mGroupsBefore: Boolean = false
|
||||
private var mAscending: Boolean = false
|
||||
private var mRecycleBinBottom: Boolean = false
|
||||
|
||||
override fun onAttach(context: Context?) {
|
||||
super.onAttach(context)
|
||||
try {
|
||||
mListener = context as SortSelectionListener?
|
||||
} catch (e: ClassCastException) {
|
||||
throw ClassCastException(context!!.toString()
|
||||
+ " must implement " + SortSelectionListener::class.java.name)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
activity?.let { activity ->
|
||||
val builder = AlertDialog.Builder(activity)
|
||||
|
||||
mSortNodeEnum = SortNodeEnum.TITLE
|
||||
mAscending = true
|
||||
mGroupsBefore = true
|
||||
var recycleBinAllowed = false
|
||||
mRecycleBinBottom = true
|
||||
|
||||
arguments?.apply {
|
||||
if (containsKey(SORT_NODE_ENUM_BUNDLE_KEY))
|
||||
getString(SORT_NODE_ENUM_BUNDLE_KEY)?.let {
|
||||
mSortNodeEnum = SortNodeEnum.valueOf(it)
|
||||
}
|
||||
if (containsKey(SORT_ASCENDING_BUNDLE_KEY))
|
||||
mAscending = getBoolean(SORT_ASCENDING_BUNDLE_KEY)
|
||||
if (containsKey(SORT_GROUPS_BEFORE_BUNDLE_KEY))
|
||||
mGroupsBefore = getBoolean(SORT_GROUPS_BEFORE_BUNDLE_KEY)
|
||||
if (containsKey(SORT_RECYCLE_BIN_BOTTOM_BUNDLE_KEY)) {
|
||||
recycleBinAllowed = true
|
||||
mRecycleBinBottom = getBoolean(SORT_RECYCLE_BIN_BOTTOM_BUNDLE_KEY)
|
||||
}
|
||||
}
|
||||
|
||||
mCheckedId = retrieveViewFromEnum(mSortNodeEnum!!)
|
||||
|
||||
val rootView = activity.layoutInflater.inflate(R.layout.sort_selection, null)
|
||||
builder.setTitle(R.string.sort_menu)
|
||||
builder.setView(rootView)
|
||||
// Add action buttons
|
||||
.setPositiveButton(android.R.string.ok
|
||||
) { _, _ -> mListener?.onSortSelected(mSortNodeEnum!!, mAscending, mGroupsBefore, mRecycleBinBottom) }
|
||||
.setNegativeButton(R.string.cancel) { _, _ -> }
|
||||
|
||||
val ascendingView = rootView.findViewById<CompoundButton>(R.id.sort_selection_ascending)
|
||||
// Check if is ascending or descending
|
||||
ascendingView.isChecked = mAscending
|
||||
ascendingView.setOnCheckedChangeListener { _, isChecked -> mAscending = isChecked }
|
||||
|
||||
val groupsBeforeView = rootView.findViewById<CompoundButton>(R.id.sort_selection_groups_before)
|
||||
// Check if groups before
|
||||
groupsBeforeView.isChecked = mGroupsBefore
|
||||
groupsBeforeView.setOnCheckedChangeListener { _, isChecked -> mGroupsBefore = isChecked }
|
||||
|
||||
val recycleBinBottomView = rootView.findViewById<CompoundButton>(R.id.sort_selection_recycle_bin_bottom)
|
||||
if (!recycleBinAllowed) {
|
||||
recycleBinBottomView.visibility = View.GONE
|
||||
} else {
|
||||
// Check if recycle bin at the bottom
|
||||
recycleBinBottomView.isChecked = mRecycleBinBottom
|
||||
recycleBinBottomView.setOnCheckedChangeListener { _, isChecked -> mRecycleBinBottom = isChecked }
|
||||
}
|
||||
|
||||
val sortSelectionRadioGroupView = rootView.findViewById<RadioGroup>(R.id.sort_selection_radio_group)
|
||||
// Check value by default
|
||||
sortSelectionRadioGroupView.check(mCheckedId)
|
||||
sortSelectionRadioGroupView.setOnCheckedChangeListener { _, checkedId -> mSortNodeEnum = retrieveSortEnumFromViewId(checkedId) }
|
||||
|
||||
return builder.create()
|
||||
}
|
||||
return super.onCreateDialog(savedInstanceState)
|
||||
}
|
||||
|
||||
@IdRes
|
||||
private fun retrieveViewFromEnum(sortNodeEnum: SortNodeEnum): Int {
|
||||
return when (sortNodeEnum) {
|
||||
SortNodeEnum.DB -> R.id.sort_selection_db
|
||||
SortNodeEnum.TITLE -> R.id.sort_selection_title
|
||||
SortNodeEnum.USERNAME -> R.id.sort_selection_username
|
||||
SortNodeEnum.CREATION_TIME -> R.id.sort_selection_creation_time
|
||||
SortNodeEnum.LAST_MODIFY_TIME -> R.id.sort_selection_last_modify_time
|
||||
SortNodeEnum.LAST_ACCESS_TIME -> R.id.sort_selection_last_access_time
|
||||
}
|
||||
}
|
||||
|
||||
private fun retrieveSortEnumFromViewId(@IdRes checkedId: Int): SortNodeEnum {
|
||||
// Change enum
|
||||
return when (checkedId) {
|
||||
R.id.sort_selection_db -> SortNodeEnum.DB
|
||||
R.id.sort_selection_title -> SortNodeEnum.TITLE
|
||||
R.id.sort_selection_username -> SortNodeEnum.USERNAME
|
||||
R.id.sort_selection_creation_time -> SortNodeEnum.CREATION_TIME
|
||||
R.id.sort_selection_last_modify_time -> SortNodeEnum.LAST_MODIFY_TIME
|
||||
R.id.sort_selection_last_access_time -> SortNodeEnum.LAST_ACCESS_TIME
|
||||
else -> SortNodeEnum.TITLE
|
||||
}
|
||||
}
|
||||
|
||||
interface SortSelectionListener {
|
||||
fun onSortSelected(sortNodeEnum: SortNodeEnum,
|
||||
ascending: Boolean,
|
||||
groupsBefore: Boolean,
|
||||
recycleBinBottom: Boolean)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val SORT_NODE_ENUM_BUNDLE_KEY = "SORT_NODE_ENUM_BUNDLE_KEY"
|
||||
private const val SORT_ASCENDING_BUNDLE_KEY = "SORT_ASCENDING_BUNDLE_KEY"
|
||||
private const val SORT_GROUPS_BEFORE_BUNDLE_KEY = "SORT_GROUPS_BEFORE_BUNDLE_KEY"
|
||||
private const val SORT_RECYCLE_BIN_BOTTOM_BUNDLE_KEY = "SORT_RECYCLE_BIN_BOTTOM_BUNDLE_KEY"
|
||||
|
||||
private fun buildBundle(sortNodeEnum: SortNodeEnum,
|
||||
ascending: Boolean,
|
||||
groupsBefore: Boolean): Bundle {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(SORT_NODE_ENUM_BUNDLE_KEY, sortNodeEnum.name)
|
||||
bundle.putBoolean(SORT_ASCENDING_BUNDLE_KEY, ascending)
|
||||
bundle.putBoolean(SORT_GROUPS_BEFORE_BUNDLE_KEY, groupsBefore)
|
||||
return bundle
|
||||
}
|
||||
|
||||
fun getInstance(sortNodeEnum: SortNodeEnum,
|
||||
ascending: Boolean,
|
||||
groupsBefore: Boolean): SortDialogFragment {
|
||||
val bundle = buildBundle(sortNodeEnum, ascending, groupsBefore)
|
||||
val fragment = SortDialogFragment()
|
||||
fragment.arguments = bundle
|
||||
return fragment
|
||||
}
|
||||
|
||||
fun getInstance(sortNodeEnum: SortNodeEnum,
|
||||
ascending: Boolean,
|
||||
groupsBefore: Boolean,
|
||||
recycleBinBottom: Boolean): SortDialogFragment {
|
||||
val bundle = buildBundle(sortNodeEnum, ascending, groupsBefore)
|
||||
bundle.putBoolean(SORT_RECYCLE_BIN_BOTTOM_BUNDLE_KEY, recycleBinBottom)
|
||||
val fragment = SortDialogFragment()
|
||||
fragment.arguments = bundle
|
||||
return fragment
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright 2019 Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* KeePass DX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.activities.dialogs
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.DialogFragment
|
||||
import android.support.v7.app.AlertDialog
|
||||
import android.text.Html
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.widget.TextView
|
||||
import com.kunzisoft.keepass.R
|
||||
|
||||
class UnavailableFeatureDialogFragment : DialogFragment() {
|
||||
private var minVersionRequired = Build.VERSION_CODES.M
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
activity?.let { activity ->
|
||||
arguments?.apply {
|
||||
if (containsKey(MIN_REQUIRED_VERSION_ARG))
|
||||
minVersionRequired = getInt(MIN_REQUIRED_VERSION_ARG)
|
||||
}
|
||||
|
||||
val rootView = activity.layoutInflater.inflate(R.layout.unavailable_feature, null)
|
||||
val messageView = rootView.findViewById<TextView>(R.id.unavailable_feature_message)
|
||||
|
||||
val builder = AlertDialog.Builder(activity)
|
||||
|
||||
val message = SpannableStringBuilder()
|
||||
message.append(getString(R.string.unavailable_feature_text))
|
||||
.append("\n\n")
|
||||
if (Build.VERSION.SDK_INT < minVersionRequired) {
|
||||
message.append(getString(R.string.unavailable_feature_version,
|
||||
androidNameFromApiNumber(Build.VERSION.SDK_INT, Build.VERSION.RELEASE),
|
||||
androidNameFromApiNumber(minVersionRequired)))
|
||||
message.append("\n\n")
|
||||
.append(Html.fromHtml("<a href=\"https://source.android.com/setup/build-numbers\">CodeNames</a>"))
|
||||
} else
|
||||
message.append(getString(R.string.unavailable_feature_hardware))
|
||||
|
||||
messageView.text = message
|
||||
messageView.movementMethod = LinkMovementMethod.getInstance()
|
||||
|
||||
builder.setView(rootView)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ -> }
|
||||
return builder.create()
|
||||
}
|
||||
return super.onCreateDialog(savedInstanceState)
|
||||
}
|
||||
|
||||
private fun androidNameFromApiNumber(apiNumber: Int, releaseVersion: String = ""): String {
|
||||
var version = releaseVersion
|
||||
val builder = StringBuilder()
|
||||
val fields = Build.VERSION_CODES::class.java.fields
|
||||
var apiName = ""
|
||||
for (field in fields) {
|
||||
val fieldName = field.name
|
||||
var fieldValue = -1
|
||||
try {
|
||||
fieldValue = field.getInt(Any())
|
||||
} catch (e: IllegalArgumentException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: IllegalAccessException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: NullPointerException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
if (fieldValue == apiNumber) {
|
||||
apiName = fieldName
|
||||
}
|
||||
}
|
||||
if (apiName.isEmpty()) {
|
||||
val mapper = arrayOf("ANDROID BASE", "ANDROID BASE 1.1", "CUPCAKE", "DONUT", "ECLAIR", "ECLAIR_0_1", "ECLAIR_MR1", "FROYO", "GINGERBREAD", "GINGERBREAD_MR1", "HONEYCOMB", "HONEYCOMB_MR1", "HONEYCOMB_MR2", "ICE_CREAM_SANDWICH", "ICE_CREAM_SANDWICH_MR1", "JELLY_BEAN", "JELLY_BEAN", "JELLY_BEAN", "KITKAT", "KITKAT", "LOLLIPOOP", "LOLLIPOOP_MR1", "MARSHMALLOW", "NOUGAT", "NOUGAT", "OREO", "OREO")
|
||||
val index = apiNumber - 1
|
||||
apiName = if (index < mapper.size) mapper[index] else "UNKNOWN_VERSION"
|
||||
}
|
||||
if (version.isEmpty()) {
|
||||
val versions = arrayOf("1.0", "1.1", "1.5", "1.6", "2.0", "2.0.1", "2.1", "2.2.X", "2.3", "2.3.3", "3.0", "3.1", "3.2.0", "4.0.1", "4.0.3", "4.1.0", "4.2.0", "4.3.0", "4.4", "4.4", "5.0", "5.1", "6.0", "7.0", "7.1", "8.0.0", "8.1.0")
|
||||
val index = apiNumber - 1
|
||||
version = if (index < versions.size) versions[index] else "UNKNOWN_VERSION"
|
||||
}
|
||||
|
||||
builder.append("\n\t")
|
||||
if (apiName.isNotEmpty())
|
||||
builder.append(apiName).append(" ")
|
||||
if (version.isNotEmpty())
|
||||
builder.append(version).append(" ")
|
||||
builder.append("(API ").append(apiNumber).append(")")
|
||||
builder.append("\n")
|
||||
return builder.toString()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val MIN_REQUIRED_VERSION_ARG = "MIN_REQUIRED_VERSION_ARG"
|
||||
|
||||
fun getInstance(minVersionRequired: Int): UnavailableFeatureDialogFragment {
|
||||
val fragment = UnavailableFeatureDialogFragment()
|
||||
val args = Bundle()
|
||||
args.putInt(MIN_REQUIRED_VERSION_ARG, minVersionRequired)
|
||||
fragment.arguments = args
|
||||
return fragment
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2019 Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* KeePass DX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.activities.dialogs
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.DialogFragment
|
||||
import android.support.v7.app.AlertDialog
|
||||
import android.text.Html
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.widget.Toast
|
||||
|
||||
import com.kunzisoft.keepass.BuildConfig
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.utils.Util
|
||||
|
||||
/**
|
||||
* Custom Dialog that asks the user to download the pro version or make a donation.
|
||||
*/
|
||||
class UnderDevelopmentFeatureDialogFragment : DialogFragment() {
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
activity?.let { activity ->
|
||||
// Use the Builder class for convenient dialog construction
|
||||
val builder = AlertDialog.Builder(activity!!)
|
||||
|
||||
val stringBuilder = SpannableStringBuilder()
|
||||
if (BuildConfig.CLOSED_STORE) {
|
||||
if (BuildConfig.FULL_VERSION) {
|
||||
stringBuilder.append(Html.fromHtml(getString(R.string.html_text_dev_feature_thanks))).append("\n\n")
|
||||
.append(Html.fromHtml(getString(R.string.html_rose))).append("\n\n")
|
||||
.append(Html.fromHtml(getString(R.string.html_text_dev_feature_work_hard))).append("\n")
|
||||
.append(Html.fromHtml(getString(R.string.html_text_dev_feature_upgrade))).append(" ")
|
||||
builder.setPositiveButton(android.R.string.ok) { dialog, id -> dismiss() }
|
||||
} else {
|
||||
stringBuilder.append(Html.fromHtml(getString(R.string.html_text_dev_feature))).append("\n\n")
|
||||
.append(Html.fromHtml(getString(R.string.html_text_dev_feature_buy_pro))).append("\n")
|
||||
.append(Html.fromHtml(getString(R.string.html_text_dev_feature_encourage)))
|
||||
builder.setPositiveButton(R.string.download) { dialog, id ->
|
||||
try {
|
||||
Util.gotoUrl(context, R.string.app_pro_url)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
Toast.makeText(context, R.string.error_failed_to_launch_link, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
builder.setNegativeButton(android.R.string.cancel) { dialog, id -> dismiss() }
|
||||
}
|
||||
} else {
|
||||
stringBuilder.append(Html.fromHtml(getString(R.string.html_text_dev_feature))).append("\n\n")
|
||||
.append(Html.fromHtml(getString(R.string.html_text_dev_feature_contibute))).append(" ")
|
||||
.append(Html.fromHtml(getString(R.string.html_text_dev_feature_encourage)))
|
||||
builder.setPositiveButton(R.string.contribute) { dialog, id ->
|
||||
try {
|
||||
Util.gotoUrl(context, R.string.contribution_url)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
Toast.makeText(context, R.string.error_failed_to_launch_link, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
builder.setNegativeButton(android.R.string.cancel) { dialog, id -> dismiss() }
|
||||
}
|
||||
builder.setMessage(stringBuilder)
|
||||
// Create the AlertDialog object and return it
|
||||
return builder.create()
|
||||
}
|
||||
return super.onCreateDialog(savedInstanceState)
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.view;
|
||||
package com.kunzisoft.keepass.activities.view;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
@@ -16,7 +16,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.kunzisoft.keepass.view
|
||||
package com.kunzisoft.keepass.activities.view
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
@@ -17,7 +17,7 @@
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.view;
|
||||
package com.kunzisoft.keepass.activities.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
@@ -17,7 +17,7 @@
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.view;
|
||||
package com.kunzisoft.keepass.activities.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.method.PasswordTransformationMethod;
|
||||
@@ -17,7 +17,7 @@
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.view;
|
||||
package com.kunzisoft.keepass.activities.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
@@ -1,216 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* KeePass DX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.dialogs;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.view.ActionMode;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.kunzisoft.keepass.activities.stylish.FilePickerStylishActivity;
|
||||
import com.kunzisoft.keepass.utils.UriUtil;
|
||||
import com.nononsenseapps.filepicker.FilePickerActivity;
|
||||
import com.nononsenseapps.filepicker.Utils;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class CreateFileDialogFragment extends DialogFragment implements AdapterView.OnItemSelectedListener{
|
||||
|
||||
private final int FILE_CODE = 3853;
|
||||
|
||||
private EditText folderPathView;
|
||||
private EditText fileNameView;
|
||||
private DefinePathDialogListener mListener;
|
||||
private String extension;
|
||||
|
||||
private Uri uriPath;
|
||||
|
||||
private Button positiveButton;
|
||||
private Button negativeButton;
|
||||
|
||||
public interface DefinePathDialogListener {
|
||||
boolean onDefinePathDialogPositiveClick(Uri pathFile);
|
||||
boolean onDefinePathDialogNegativeClick(Uri pathFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context activity) {
|
||||
super.onAttach(activity);
|
||||
try {
|
||||
mListener = (DefinePathDialogListener) activity;
|
||||
} catch (ClassCastException e) {
|
||||
throw new ClassCastException(activity.toString()
|
||||
+ " must implement " + DefinePathDialogListener.class.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
assert getActivity() != null;
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
LayoutInflater inflater = getActivity().getLayoutInflater();
|
||||
|
||||
View rootView = inflater.inflate(R.layout.file_creation, null);
|
||||
builder.setView(rootView)
|
||||
.setTitle(R.string.create_keepass_file)
|
||||
// Add action buttons
|
||||
.setPositiveButton(android.R.string.ok, (dialog, id) -> {})
|
||||
.setNegativeButton(R.string.cancel, (dialog, id) -> {});
|
||||
|
||||
// To prevent crash issue #69 https://github.com/Kunzisoft/KeePassDX/issues/69
|
||||
ActionMode.Callback actionCopyBarCallback = new ActionMode.Callback() {
|
||||
|
||||
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
|
||||
if (positiveButton != null && negativeButton != null) {
|
||||
positiveButton.setEnabled(false);
|
||||
negativeButton.setEnabled(false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void onDestroyActionMode(ActionMode mode) {
|
||||
if (positiveButton != null && negativeButton != null) {
|
||||
positiveButton.setEnabled(true);
|
||||
negativeButton.setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// Folder selection
|
||||
View browseView = rootView.findViewById(R.id.browse_button);
|
||||
folderPathView = rootView.findViewById(R.id.folder_path);
|
||||
folderPathView.setCustomSelectionActionModeCallback(actionCopyBarCallback);
|
||||
fileNameView = rootView.findViewById(R.id.filename);
|
||||
fileNameView.setCustomSelectionActionModeCallback(actionCopyBarCallback);
|
||||
|
||||
String defaultPath = Environment.getExternalStorageDirectory().getPath()
|
||||
+ getString(R.string.database_file_path_default);
|
||||
folderPathView.setText(defaultPath);
|
||||
browseView.setOnClickListener(v -> {
|
||||
Intent i = new Intent(getContext(), FilePickerStylishActivity.class);
|
||||
i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false);
|
||||
i.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, true);
|
||||
i.putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_DIR);
|
||||
i.putExtra(FilePickerActivity.EXTRA_START_PATH,
|
||||
Environment.getExternalStorageDirectory().getPath());
|
||||
startActivityForResult(i, FILE_CODE);
|
||||
});
|
||||
|
||||
// Init path
|
||||
uriPath = null;
|
||||
|
||||
// Extension
|
||||
extension = getString(R.string.database_file_extension_default);
|
||||
Spinner spinner = rootView.findViewById(R.id.file_types);
|
||||
spinner.setOnItemSelectedListener(this);
|
||||
|
||||
// Spinner Drop down elements
|
||||
String[] fileTypes = getResources().getStringArray(R.array.file_types);
|
||||
ArrayAdapter<String> dataAdapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_spinner_item, fileTypes);
|
||||
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
spinner.setAdapter(dataAdapter);
|
||||
// Or text if only one item https://github.com/Kunzisoft/KeePassDX/issues/105
|
||||
if (fileTypes.length == 1) {
|
||||
ViewGroup.LayoutParams params = spinner.getLayoutParams();
|
||||
spinner.setVisibility(View.GONE);
|
||||
TextView extensionTextView = new TextView(getContext());
|
||||
extensionTextView.setText(extension);
|
||||
extensionTextView.setLayoutParams(params);
|
||||
ViewGroup parentView = (ViewGroup) spinner.getParent();
|
||||
parentView.addView(extensionTextView);
|
||||
}
|
||||
|
||||
AlertDialog dialog = builder.create();
|
||||
|
||||
dialog.setOnShowListener(dialog1 -> {
|
||||
positiveButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
|
||||
negativeButton = dialog.getButton(DialogInterface.BUTTON_NEGATIVE);
|
||||
positiveButton.setOnClickListener(v -> {
|
||||
if(mListener.onDefinePathDialogPositiveClick(buildPath()))
|
||||
dismiss();
|
||||
});
|
||||
negativeButton.setOnClickListener(v -> {
|
||||
if(mListener.onDefinePathDialogNegativeClick(buildPath())) {
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (data != null && requestCode == FILE_CODE && resultCode == Activity.RESULT_OK) {
|
||||
uriPath = data.getData();
|
||||
if (uriPath != null) {
|
||||
File file = Utils.getFileForUri(uriPath);
|
||||
folderPathView.setText(file.getPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
|
||||
extension = adapterView.getItemAtPosition(position).toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> adapterView) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
private Uri buildPath() {
|
||||
Uri path = new Uri.Builder().path(folderPathView.getText().toString())
|
||||
.appendPath(fileNameView.getText().toString() + extension)
|
||||
.build();
|
||||
path = UriUtil.translate(getContext(), path);
|
||||
return path;
|
||||
}
|
||||
}
|
||||
@@ -1,214 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* KeePass DX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.dialogs;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.EditText;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.kunzisoft.keepass.password.PasswordGenerator;
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil;
|
||||
import com.kunzisoft.keepass.utils.Util;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class GeneratePasswordDialogFragment extends DialogFragment {
|
||||
|
||||
public static final String KEY_PASSWORD_ID = "KEY_PASSWORD_ID";
|
||||
|
||||
private GeneratePasswordListener mListener;
|
||||
private View root;
|
||||
private EditText lengthTextView;
|
||||
private EditText passwordView;
|
||||
|
||||
private CompoundButton uppercaseBox;
|
||||
private CompoundButton lowercaseBox;
|
||||
private CompoundButton digitsBox;
|
||||
private CompoundButton minusBox;
|
||||
private CompoundButton underlineBox;
|
||||
private CompoundButton spaceBox;
|
||||
private CompoundButton specialsBox;
|
||||
private CompoundButton bracketsBox;
|
||||
private CompoundButton extendedBox;
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
try {
|
||||
mListener = (GeneratePasswordListener) context;
|
||||
} catch (ClassCastException e) {
|
||||
throw new ClassCastException(context.toString()
|
||||
+ " must implement " + GeneratePasswordListener.class.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
LayoutInflater inflater = getActivity().getLayoutInflater();
|
||||
root = inflater.inflate(R.layout.generate_password, null);
|
||||
|
||||
passwordView = root.findViewById(R.id.password);
|
||||
Util.applyFontVisibilityTo(getContext(), passwordView);
|
||||
|
||||
lengthTextView = root.findViewById(R.id.length);
|
||||
|
||||
uppercaseBox = root.findViewById(R.id.cb_uppercase);
|
||||
lowercaseBox = root.findViewById(R.id.cb_lowercase);
|
||||
digitsBox = root.findViewById(R.id.cb_digits);
|
||||
minusBox = root.findViewById(R.id.cb_minus);
|
||||
underlineBox = root.findViewById(R.id.cb_underline);
|
||||
spaceBox = root.findViewById(R.id.cb_space);
|
||||
specialsBox = root.findViewById(R.id.cb_specials);
|
||||
bracketsBox = root.findViewById(R.id.cb_brackets);
|
||||
extendedBox = root.findViewById(R.id.cb_extended);
|
||||
|
||||
assignDefaultCharacters();
|
||||
|
||||
SeekBar seekBar = root.findViewById(R.id.seekbar_length);
|
||||
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
lengthTextView.setText(String.valueOf(progress));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {}
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {}
|
||||
});
|
||||
seekBar.setProgress(PreferencesUtil.getDefaultPasswordLength(getContext()));
|
||||
|
||||
Button genPassButton = root.findViewById(R.id.generate_password_button);
|
||||
genPassButton.setOnClickListener(v -> fillPassword());
|
||||
|
||||
builder.setView(root)
|
||||
.setPositiveButton(R.string.accept, (dialog, id) -> {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(KEY_PASSWORD_ID, passwordView.getText().toString());
|
||||
mListener.acceptPassword(bundle);
|
||||
|
||||
dismiss();
|
||||
})
|
||||
.setNegativeButton(R.string.cancel, (dialog, id) -> {
|
||||
Bundle bundle = new Bundle();
|
||||
mListener.cancelPassword(bundle);
|
||||
|
||||
dismiss();
|
||||
});
|
||||
|
||||
// Pre-populate a password to possibly save the user a few clicks
|
||||
fillPassword();
|
||||
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
private void assignDefaultCharacters() {
|
||||
uppercaseBox.setChecked(false);
|
||||
lowercaseBox.setChecked(false);
|
||||
digitsBox.setChecked(false);
|
||||
minusBox.setChecked(false);
|
||||
underlineBox.setChecked(false);
|
||||
spaceBox.setChecked(false);
|
||||
specialsBox.setChecked(false);
|
||||
bracketsBox.setChecked(false);
|
||||
extendedBox.setChecked(false);
|
||||
|
||||
Set<String> defaultPasswordChars =
|
||||
PreferencesUtil.getDefaultPasswordCharacters(getContext());
|
||||
for(String passwordChar : defaultPasswordChars) {
|
||||
if (passwordChar.equals(getString(R.string.value_password_uppercase))) {
|
||||
uppercaseBox.setChecked(true);
|
||||
}
|
||||
else if (passwordChar.equals(getString(R.string.value_password_lowercase))) {
|
||||
lowercaseBox.setChecked(true);
|
||||
}
|
||||
else if (passwordChar.equals(getString(R.string.value_password_digits))) {
|
||||
digitsBox.setChecked(true);
|
||||
}
|
||||
else if (passwordChar.equals(getString(R.string.value_password_minus))) {
|
||||
minusBox.setChecked(true);
|
||||
}
|
||||
else if (passwordChar.equals(getString(R.string.value_password_underline))) {
|
||||
underlineBox.setChecked(true);
|
||||
}
|
||||
else if (passwordChar.equals(getString(R.string.value_password_space))) {
|
||||
spaceBox.setChecked(true);
|
||||
}
|
||||
else if (passwordChar.equals(getString(R.string.value_password_special))) {
|
||||
specialsBox.setChecked(true);
|
||||
}
|
||||
else if (passwordChar.equals(getString(R.string.value_password_brackets))) {
|
||||
bracketsBox.setChecked(true);
|
||||
}
|
||||
else if (passwordChar.equals(getString(R.string.value_password_extended))) {
|
||||
extendedBox.setChecked(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fillPassword() {
|
||||
EditText txtPassword = root.findViewById(R.id.password);
|
||||
txtPassword.setText(generatePassword());
|
||||
}
|
||||
|
||||
public String generatePassword() {
|
||||
String password = "";
|
||||
try {
|
||||
int length = Integer.valueOf(((EditText) root.findViewById(R.id.length)).getText().toString());
|
||||
|
||||
PasswordGenerator generator = new PasswordGenerator(getActivity());
|
||||
password = generator.generatePassword(length,
|
||||
uppercaseBox.isChecked(),
|
||||
lowercaseBox.isChecked(),
|
||||
digitsBox.isChecked(),
|
||||
minusBox.isChecked(),
|
||||
underlineBox.isChecked(),
|
||||
spaceBox.isChecked(),
|
||||
specialsBox.isChecked(),
|
||||
bracketsBox.isChecked(),
|
||||
extendedBox.isChecked());
|
||||
} catch (NumberFormatException e) {
|
||||
Toast.makeText(getContext(), R.string.error_wrong_length, Toast.LENGTH_LONG).show();
|
||||
} catch (IllegalArgumentException e) {
|
||||
Toast.makeText(getContext(), e.getMessage(), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
return password;
|
||||
}
|
||||
|
||||
public interface GeneratePasswordListener {
|
||||
void acceptPassword(Bundle bundle);
|
||||
void cancelPassword(Bundle bundle);
|
||||
}
|
||||
}
|
||||
@@ -1,216 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* KeePass DX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.dialogs;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.kunzisoft.keepass.app.App;
|
||||
import com.kunzisoft.keepass.database.element.Database;
|
||||
import com.kunzisoft.keepass.database.element.GroupVersioned;
|
||||
import com.kunzisoft.keepass.database.element.PwIcon;
|
||||
|
||||
import static com.kunzisoft.keepass.dialogs.GroupEditDialogFragment.EditGroupDialogAction.CREATION;
|
||||
import static com.kunzisoft.keepass.dialogs.GroupEditDialogFragment.EditGroupDialogAction.UPDATE;
|
||||
import static com.kunzisoft.keepass.dialogs.GroupEditDialogFragment.EditGroupDialogAction.getActionFromOrdinal;
|
||||
|
||||
public class GroupEditDialogFragment extends DialogFragment
|
||||
implements IconPickerDialogFragment.IconPickerListener {
|
||||
|
||||
public static final String TAG_CREATE_GROUP = "TAG_CREATE_GROUP";
|
||||
|
||||
public static final String KEY_NAME = "KEY_NAME";
|
||||
public static final String KEY_ICON = "KEY_ICON";
|
||||
public static final String KEY_ACTION_ID = "KEY_ACTION_ID";
|
||||
|
||||
private Database database;
|
||||
|
||||
private EditGroupListener editGroupListener;
|
||||
|
||||
private EditGroupDialogAction editGroupDialogAction;
|
||||
private String nameGroup;
|
||||
private PwIcon iconGroup;
|
||||
|
||||
private ImageView iconButton;
|
||||
private int iconColor;
|
||||
|
||||
public enum EditGroupDialogAction {
|
||||
CREATION, UPDATE, NONE;
|
||||
|
||||
public static EditGroupDialogAction getActionFromOrdinal(int ordinal) {
|
||||
return EditGroupDialogAction.values()[ordinal];
|
||||
}
|
||||
}
|
||||
|
||||
public static GroupEditDialogFragment build() {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt(KEY_ACTION_ID, CREATION.ordinal());
|
||||
GroupEditDialogFragment fragment = new GroupEditDialogFragment();
|
||||
fragment.setArguments(bundle);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
public static GroupEditDialogFragment build(GroupVersioned group) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(KEY_NAME, group.getTitle());
|
||||
bundle.putParcelable(KEY_ICON, group.getIcon());
|
||||
bundle.putInt(KEY_ACTION_ID, UPDATE.ordinal());
|
||||
GroupEditDialogFragment fragment = new GroupEditDialogFragment();
|
||||
fragment.setArguments(bundle);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
// Verify that the host activity implements the callback interface
|
||||
try {
|
||||
// Instantiate the NoticeDialogListener so we can send events to the host
|
||||
editGroupListener = (EditGroupListener) context;
|
||||
} catch (ClassCastException e) {
|
||||
// The activity doesn't implement the interface, throw exception
|
||||
throw new ClassCastException(context.toString()
|
||||
+ " must implement " + GroupEditDialogFragment.class.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
assert getActivity() != null;
|
||||
LayoutInflater inflater = getActivity().getLayoutInflater();
|
||||
View root = inflater.inflate(R.layout.group_edit, null);
|
||||
TextView nameField = root.findViewById(R.id.group_edit_name);
|
||||
iconButton = root.findViewById(R.id.group_edit_icon_button);
|
||||
|
||||
// Retrieve the textColor to tint the icon
|
||||
int[] attrs = {android.R.attr.textColorPrimary};
|
||||
TypedArray ta = getActivity().getTheme().obtainStyledAttributes(attrs);
|
||||
iconColor = ta.getColor(0, Color.WHITE);
|
||||
ta.recycle();
|
||||
|
||||
// Init elements
|
||||
database = App.Companion.getCurrentDatabase();
|
||||
editGroupDialogAction = EditGroupDialogAction.NONE;
|
||||
nameGroup = "";
|
||||
iconGroup = database.getIconFactory().getFolderIcon();
|
||||
|
||||
if (savedInstanceState != null
|
||||
&& savedInstanceState.containsKey(KEY_ACTION_ID)
|
||||
&& savedInstanceState.containsKey(KEY_NAME)
|
||||
&& savedInstanceState.containsKey(KEY_ICON)) {
|
||||
editGroupDialogAction = getActionFromOrdinal(savedInstanceState.getInt(KEY_ACTION_ID));
|
||||
nameGroup = savedInstanceState.getString(KEY_NAME);
|
||||
iconGroup = savedInstanceState.getParcelable(KEY_ICON);
|
||||
|
||||
} else {
|
||||
|
||||
if (getArguments() != null
|
||||
&& getArguments().containsKey(KEY_ACTION_ID))
|
||||
editGroupDialogAction = EditGroupDialogAction.getActionFromOrdinal(getArguments().getInt(KEY_ACTION_ID));
|
||||
|
||||
if (getArguments() != null
|
||||
&& getArguments().containsKey(KEY_NAME)
|
||||
&& getArguments().containsKey(KEY_ICON)) {
|
||||
nameGroup = getArguments().getString(KEY_NAME);
|
||||
iconGroup = getArguments().getParcelable(KEY_ICON);
|
||||
}
|
||||
}
|
||||
|
||||
// populate the name
|
||||
nameField.setText(nameGroup);
|
||||
// populate the icon
|
||||
assignIconView();
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
builder.setView(root)
|
||||
.setPositiveButton(android.R.string.ok, (dialog, id) -> {
|
||||
String name = nameField.getText().toString();
|
||||
if ( name.length() > 0 ) {
|
||||
editGroupListener.approveEditGroup(
|
||||
editGroupDialogAction,
|
||||
name,
|
||||
iconGroup);
|
||||
|
||||
GroupEditDialogFragment.this.getDialog().cancel();
|
||||
}
|
||||
else {
|
||||
Toast.makeText(getContext(), R.string.error_no_name, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.cancel, (dialog, id) -> {
|
||||
String name = nameField.getText().toString();
|
||||
editGroupListener.cancelEditGroup(
|
||||
editGroupDialogAction,
|
||||
name,
|
||||
iconGroup);
|
||||
|
||||
GroupEditDialogFragment.this.getDialog().cancel();
|
||||
});
|
||||
|
||||
iconButton.setOnClickListener(v -> {
|
||||
IconPickerDialogFragment iconPickerDialogFragment = new IconPickerDialogFragment();
|
||||
if (getFragmentManager() != null)
|
||||
iconPickerDialogFragment.show(getFragmentManager(), "IconPickerDialogFragment");
|
||||
});
|
||||
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
private void assignIconView() {
|
||||
database.getDrawFactory()
|
||||
.assignDatabaseIconTo(
|
||||
getContext(),
|
||||
iconButton,
|
||||
iconGroup,
|
||||
iconColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void iconPicked(Bundle bundle) {
|
||||
iconGroup = bundle.getParcelable(IconPickerDialogFragment.KEY_ICON_STANDARD);
|
||||
assignIconView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
outState.putInt(KEY_ACTION_ID, editGroupDialogAction.ordinal());
|
||||
outState.putString(KEY_NAME, nameGroup);
|
||||
outState.putParcelable(KEY_ICON, iconGroup);
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
public interface EditGroupListener {
|
||||
void approveEditGroup(EditGroupDialogAction action, String name, PwIcon selectedIcon);
|
||||
void cancelEditGroup(EditGroupDialogAction action, String name, PwIcon selectedIcon);
|
||||
}
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* KeePass DX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.dialogs;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v4.widget.ImageViewCompat;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.GridView;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.kunzisoft.keepass.database.element.PwIconStandard;
|
||||
import com.kunzisoft.keepass.icons.IconPack;
|
||||
import com.kunzisoft.keepass.icons.IconPackChooser;
|
||||
import com.kunzisoft.keepass.activities.stylish.StylishActivity;
|
||||
|
||||
|
||||
public class IconPickerDialogFragment extends DialogFragment {
|
||||
|
||||
public static final String KEY_ICON_STANDARD = "KEY_ICON_STANDARD";
|
||||
|
||||
private IconPickerListener iconPickerListener;
|
||||
private IconPack iconPack;
|
||||
|
||||
public static void launch(StylishActivity activity) {
|
||||
// Create an instance of the dialog fragment and show it
|
||||
IconPickerDialogFragment dialog = new IconPickerDialogFragment();
|
||||
dialog.show(activity.getSupportFragmentManager(), "IconPickerDialogFragment");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
try {
|
||||
iconPickerListener = (IconPickerListener) context;
|
||||
} catch (ClassCastException e) {
|
||||
// The activity doesn't implement the interface, throw exception
|
||||
throw new ClassCastException(context.toString()
|
||||
+ " must implement " + IconPickerListener.class.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
// Get the layout inflater
|
||||
LayoutInflater inflater = getActivity().getLayoutInflater();
|
||||
|
||||
iconPack = IconPackChooser.getSelectedIconPack(getContext());
|
||||
|
||||
// Inflate and set the layout for the dialog
|
||||
// Pass null as the parent view because its going in the dialog layout
|
||||
View root = inflater.inflate(R.layout.icon_picker, null);
|
||||
builder.setView(root);
|
||||
|
||||
GridView currIconGridView = root.findViewById(R.id.IconGridView);
|
||||
currIconGridView.setAdapter(new ImageAdapter(this.getContext()));
|
||||
|
||||
currIconGridView.setOnItemClickListener((parent, v, position, id) -> {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelable(KEY_ICON_STANDARD, new PwIconStandard(position));
|
||||
iconPickerListener.iconPicked(bundle);
|
||||
dismiss();
|
||||
});
|
||||
|
||||
builder.setNegativeButton(R.string.cancel, (dialog, id) ->
|
||||
IconPickerDialogFragment.this.getDialog().cancel());
|
||||
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
public class ImageAdapter extends BaseAdapter {
|
||||
private Context context;
|
||||
|
||||
ImageAdapter(Context c) {
|
||||
context = c;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
/* Return number of KeePass icons */
|
||||
return iconPack.numberOfIcons();
|
||||
}
|
||||
|
||||
public Object getItem(int position) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public long getItemId(int position) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
View currView;
|
||||
if(convertView == null) {
|
||||
LayoutInflater li = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
assert li != null;
|
||||
currView = li.inflate(R.layout.icon, parent, false);
|
||||
}
|
||||
else {
|
||||
currView = convertView;
|
||||
}
|
||||
ImageView iv = currView.findViewById(R.id.icon_image);
|
||||
iv.setImageResource(iconPack.iconToResId(position));
|
||||
|
||||
// Assign color if icons are tintable
|
||||
if (iconPack.tintable()) {
|
||||
// Retrieve the textColor to tint the icon
|
||||
int[] attrs = {android.R.attr.textColor};
|
||||
assert getContext() != null;
|
||||
TypedArray ta = getContext().getTheme().obtainStyledAttributes(attrs);
|
||||
int iconColor = ta.getColor(0, Color.BLACK);
|
||||
ImageViewCompat.setImageTintList(iv, ColorStateList.valueOf(iconColor));
|
||||
ta.recycle();
|
||||
}
|
||||
|
||||
return currView;
|
||||
}
|
||||
}
|
||||
|
||||
public interface IconPickerListener {
|
||||
void iconPicked(Bundle bundle);
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* KeePass DX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.dialogs;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
||||
import com.kunzisoft.keepass.BuildConfig;
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.kunzisoft.keepass.utils.Util;
|
||||
|
||||
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
||||
|
||||
public class KeyboardExplanationDialogFragment extends DialogFragment {
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
assert getActivity() != null;
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
LayoutInflater inflater = getActivity().getLayoutInflater();
|
||||
|
||||
View rootView = inflater.inflate(R.layout.keyboard_explanation, null);
|
||||
|
||||
View fingerprintSettingPath1TextView = rootView.findViewById(R.id.keyboards_activate_setting_path1_text);
|
||||
fingerprintSettingPath1TextView.setOnClickListener(
|
||||
view -> launchActivateKeyboardSetting());
|
||||
View fingerprintSettingPath2TextView = rootView.findViewById(R.id.keyboards_activate_setting_path2_text);
|
||||
fingerprintSettingPath2TextView.setOnClickListener(
|
||||
view -> launchActivateKeyboardSetting());
|
||||
|
||||
View containerKeyboardSwitcher = rootView.findViewById(R.id.container_keyboard_switcher);
|
||||
if(BuildConfig.CLOSED_STORE) {
|
||||
containerKeyboardSwitcher.setOnClickListener(
|
||||
view -> Util.gotoUrl(getContext(), R.string.keyboard_switcher_play_store));
|
||||
} else {
|
||||
containerKeyboardSwitcher.setOnClickListener(
|
||||
view -> Util.gotoUrl(getContext(), R.string.keyboard_switcher_f_droid));
|
||||
}
|
||||
|
||||
builder.setView(rootView)
|
||||
.setPositiveButton(android.R.string.ok, (dialog, id) -> {});
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
private void launchActivateKeyboardSetting() {
|
||||
Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS);
|
||||
intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(intent);
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* KeePass DX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.dialogs;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.text.Html;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.kunzisoft.keepass.BuildConfig;
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.kunzisoft.keepass.utils.Util;
|
||||
|
||||
/**
|
||||
* Custom Dialog that asks the user to download the pro version or make a donation.
|
||||
*/
|
||||
public class ProFeatureDialogFragment extends DialogFragment {
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
// Use the Builder class for convenient dialog construction
|
||||
assert getActivity() != null;
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
|
||||
SpannableStringBuilder stringBuilder = new SpannableStringBuilder();
|
||||
if (BuildConfig.CLOSED_STORE) {
|
||||
stringBuilder.append(Html.fromHtml(getString(R.string.html_text_ad_free))).append("\n\n");
|
||||
stringBuilder.append(Html.fromHtml(getString(R.string.html_text_buy_pro)));
|
||||
builder.setPositiveButton(R.string.download, (dialog, id) -> {
|
||||
try {
|
||||
Util.gotoUrl(getContext(), R.string.app_pro_url);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Toast.makeText(getContext(), R.string.error_failed_to_launch_link, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
stringBuilder.append(Html.fromHtml(getString(R.string.html_text_feature_generosity))).append("\n\n");
|
||||
stringBuilder.append(Html.fromHtml(getString(R.string.html_text_donation)));
|
||||
builder.setPositiveButton(R.string.contribute, (dialog, id) -> {
|
||||
try {
|
||||
Util.gotoUrl(getContext(), R.string.contribution_url);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Toast.makeText(getContext(), R.string.error_failed_to_launch_link, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
builder.setMessage(stringBuilder);
|
||||
builder.setNegativeButton(android.R.string.cancel, (dialog, id) -> dismiss());
|
||||
// Create the AlertDialog object and return it
|
||||
return builder.create();
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* KeePass DX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.dialogs;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
|
||||
public class ReadOnlyDialog extends WarningDialog {
|
||||
|
||||
public ReadOnlyDialog(Context context) {
|
||||
super(context, R.string.show_read_only_warning);
|
||||
|
||||
warning = context.getString(R.string.read_only_warning);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
warning = warning.concat("\n\n").concat(context.getString(R.string.read_only_kitkat_warning));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,213 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* KeePass DX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.dialogs;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.IdRes;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.RadioGroup;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.kunzisoft.keepass.database.SortNodeEnum;
|
||||
|
||||
public class SortDialogFragment extends DialogFragment {
|
||||
|
||||
private static final String SORT_NODE_ENUM_BUNDLE_KEY = "SORT_NODE_ENUM_BUNDLE_KEY";
|
||||
private static final String SORT_ASCENDING_BUNDLE_KEY = "SORT_ASCENDING_BUNDLE_KEY";
|
||||
private static final String SORT_GROUPS_BEFORE_BUNDLE_KEY = "SORT_GROUPS_BEFORE_BUNDLE_KEY";
|
||||
private static final String SORT_RECYCLE_BIN_BOTTOM_BUNDLE_KEY = "SORT_RECYCLE_BIN_BOTTOM_BUNDLE_KEY";
|
||||
|
||||
private SortSelectionListener mListener;
|
||||
|
||||
private SortNodeEnum sortNodeEnum;
|
||||
private @IdRes
|
||||
int mCheckedId;
|
||||
private boolean mGroupsBefore;
|
||||
private boolean mAscending;
|
||||
private boolean mRecycleBinBottom;
|
||||
|
||||
private static Bundle buildBundle(SortNodeEnum sortNodeEnum,
|
||||
boolean ascending,
|
||||
boolean groupsBefore) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(SORT_NODE_ENUM_BUNDLE_KEY, sortNodeEnum.name());
|
||||
bundle.putBoolean(SORT_ASCENDING_BUNDLE_KEY, ascending);
|
||||
bundle.putBoolean(SORT_GROUPS_BEFORE_BUNDLE_KEY, groupsBefore);
|
||||
return bundle;
|
||||
}
|
||||
|
||||
public static SortDialogFragment getInstance(SortNodeEnum sortNodeEnum,
|
||||
boolean ascending,
|
||||
boolean groupsBefore) {
|
||||
Bundle bundle = buildBundle(sortNodeEnum, ascending, groupsBefore);
|
||||
SortDialogFragment fragment = new SortDialogFragment();
|
||||
fragment.setArguments(bundle);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
public static SortDialogFragment getInstance(SortNodeEnum sortNodeEnum,
|
||||
boolean ascending,
|
||||
boolean groupsBefore,
|
||||
boolean recycleBinBottom) {
|
||||
Bundle bundle = buildBundle(sortNodeEnum, ascending, groupsBefore);
|
||||
bundle.putBoolean(SORT_RECYCLE_BIN_BOTTOM_BUNDLE_KEY, recycleBinBottom);
|
||||
SortDialogFragment fragment = new SortDialogFragment();
|
||||
fragment.setArguments(bundle);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
try {
|
||||
mListener = (SortSelectionListener) context;
|
||||
} catch (ClassCastException e) {
|
||||
throw new ClassCastException(context.toString()
|
||||
+ " must implement " + SortSelectionListener.class.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
assert getActivity() != null;
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
LayoutInflater inflater = getActivity().getLayoutInflater();
|
||||
|
||||
sortNodeEnum = SortNodeEnum.TITLE;
|
||||
mAscending = true;
|
||||
mGroupsBefore = true;
|
||||
boolean recycleBinAllowed = false;
|
||||
mRecycleBinBottom = true;
|
||||
|
||||
if (getArguments() != null) {
|
||||
if (getArguments().containsKey(SORT_NODE_ENUM_BUNDLE_KEY))
|
||||
sortNodeEnum = SortNodeEnum.valueOf(getArguments().getString(SORT_NODE_ENUM_BUNDLE_KEY));
|
||||
if (getArguments().containsKey(SORT_ASCENDING_BUNDLE_KEY))
|
||||
mAscending = getArguments().getBoolean(SORT_ASCENDING_BUNDLE_KEY);
|
||||
if (getArguments().containsKey(SORT_GROUPS_BEFORE_BUNDLE_KEY))
|
||||
mGroupsBefore = getArguments().getBoolean(SORT_GROUPS_BEFORE_BUNDLE_KEY);
|
||||
if (getArguments().containsKey(SORT_RECYCLE_BIN_BOTTOM_BUNDLE_KEY)) {
|
||||
recycleBinAllowed = true;
|
||||
mRecycleBinBottom = getArguments().getBoolean(SORT_RECYCLE_BIN_BOTTOM_BUNDLE_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
mCheckedId = retrieveViewFromEnum(sortNodeEnum);
|
||||
|
||||
View rootView = inflater.inflate(R.layout.sort_selection, null);
|
||||
builder.setTitle(R.string.sort_menu);
|
||||
builder.setView(rootView)
|
||||
// Add action buttons
|
||||
.setPositiveButton(android.R.string.ok,
|
||||
(dialog, id) -> mListener.onSortSelected(sortNodeEnum, mAscending, mGroupsBefore, mRecycleBinBottom))
|
||||
.setNegativeButton(R.string.cancel, (dialog, id) -> {});
|
||||
|
||||
CompoundButton ascendingView = rootView.findViewById(R.id.sort_selection_ascending);
|
||||
// Check if is ascending or descending
|
||||
ascendingView.setChecked(mAscending);
|
||||
ascendingView.setOnCheckedChangeListener(
|
||||
(buttonView, isChecked) -> mAscending = isChecked);
|
||||
|
||||
CompoundButton groupsBeforeView = rootView.findViewById(R.id.sort_selection_groups_before);
|
||||
// Check if groups before
|
||||
groupsBeforeView.setChecked(mGroupsBefore);
|
||||
groupsBeforeView.setOnCheckedChangeListener(
|
||||
(buttonView, isChecked) -> mGroupsBefore = isChecked);
|
||||
|
||||
CompoundButton recycleBinBottomView = rootView.findViewById(R.id.sort_selection_recycle_bin_bottom);
|
||||
if (!recycleBinAllowed) {
|
||||
recycleBinBottomView.setVisibility(View.GONE);
|
||||
} else {
|
||||
// Check if recycle bin at the bottom
|
||||
recycleBinBottomView.setChecked(mRecycleBinBottom);
|
||||
recycleBinBottomView.setOnCheckedChangeListener(
|
||||
(buttonView, isChecked) -> mRecycleBinBottom = isChecked);
|
||||
}
|
||||
|
||||
RadioGroup sortSelectionRadioGroupView = rootView.findViewById(R.id.sort_selection_radio_group);
|
||||
// Check value by default
|
||||
sortSelectionRadioGroupView.check(mCheckedId);
|
||||
sortSelectionRadioGroupView.setOnCheckedChangeListener(
|
||||
(group, checkedId) -> sortNodeEnum = retrieveSortEnumFromViewId(checkedId));
|
||||
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
private @IdRes
|
||||
int retrieveViewFromEnum(SortNodeEnum sortNodeEnum) {
|
||||
switch (sortNodeEnum) {
|
||||
case DB:
|
||||
return R.id.sort_selection_db;
|
||||
default:
|
||||
case TITLE:
|
||||
return R.id.sort_selection_title;
|
||||
case USERNAME:
|
||||
return R.id.sort_selection_username;
|
||||
case CREATION_TIME:
|
||||
return R.id.sort_selection_creation_time;
|
||||
case LAST_MODIFY_TIME:
|
||||
return R.id.sort_selection_last_modify_time;
|
||||
case LAST_ACCESS_TIME:
|
||||
return R.id.sort_selection_last_access_time;
|
||||
}
|
||||
}
|
||||
|
||||
private SortNodeEnum retrieveSortEnumFromViewId(@IdRes int checkedId) {
|
||||
SortNodeEnum sortNodeEnum;
|
||||
// Change enum
|
||||
switch (checkedId) {
|
||||
case R.id.sort_selection_db:
|
||||
sortNodeEnum = SortNodeEnum.DB;
|
||||
break;
|
||||
default:
|
||||
case R.id.sort_selection_title:
|
||||
sortNodeEnum = SortNodeEnum.TITLE;
|
||||
break;
|
||||
case R.id.sort_selection_username:
|
||||
sortNodeEnum = SortNodeEnum.USERNAME;
|
||||
break;
|
||||
case R.id.sort_selection_creation_time:
|
||||
sortNodeEnum = SortNodeEnum.CREATION_TIME;
|
||||
break;
|
||||
case R.id.sort_selection_last_modify_time:
|
||||
sortNodeEnum = SortNodeEnum.LAST_MODIFY_TIME;
|
||||
break;
|
||||
case R.id.sort_selection_last_access_time:
|
||||
sortNodeEnum = SortNodeEnum.LAST_ACCESS_TIME;
|
||||
break;
|
||||
}
|
||||
return sortNodeEnum;
|
||||
}
|
||||
|
||||
public interface SortSelectionListener {
|
||||
void onSortSelected(SortNodeEnum sortNodeEnum,
|
||||
boolean ascending,
|
||||
boolean groupsBefore,
|
||||
boolean recycleBinBottom);
|
||||
}
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* KeePass DX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.dialogs;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.text.Html;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class UnavailableFeatureDialogFragment extends DialogFragment {
|
||||
|
||||
private static final String MIN_REQUIRED_VERSION_ARG = "MIN_REQUIRED_VERSION_ARG";
|
||||
private int minVersionRequired = Build.VERSION_CODES.M;
|
||||
|
||||
public static UnavailableFeatureDialogFragment getInstance(int minVersionRequired) {
|
||||
UnavailableFeatureDialogFragment fragment = new UnavailableFeatureDialogFragment();
|
||||
Bundle args = new Bundle();
|
||||
args.putInt(MIN_REQUIRED_VERSION_ARG, minVersionRequired);
|
||||
fragment.setArguments(args);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
if (getArguments() != null && getArguments().containsKey(MIN_REQUIRED_VERSION_ARG))
|
||||
minVersionRequired = getArguments().getInt(MIN_REQUIRED_VERSION_ARG);
|
||||
|
||||
assert getActivity() != null;
|
||||
LayoutInflater inflater = getActivity().getLayoutInflater();
|
||||
View rootView = inflater.inflate(R.layout.unavailable_feature, null);
|
||||
TextView messageView = rootView.findViewById(R.id.unavailable_feature_message);
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
|
||||
SpannableStringBuilder message = new SpannableStringBuilder();
|
||||
message.append(getString(R.string.unavailable_feature_text))
|
||||
.append("\n\n");
|
||||
if(Build.VERSION.SDK_INT < minVersionRequired) {
|
||||
message.append(getString(R.string.unavailable_feature_version,
|
||||
androidNameFromApiNumber(Build.VERSION.SDK_INT, Build.VERSION.RELEASE),
|
||||
androidNameFromApiNumber(minVersionRequired)));
|
||||
message.append("\n\n")
|
||||
.append(Html.fromHtml("<a href=\"https://source.android.com/setup/build-numbers\">CodeNames</a>"));
|
||||
} else
|
||||
message.append(getString(R.string.unavailable_feature_hardware));
|
||||
|
||||
messageView.setText(message);
|
||||
messageView.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
|
||||
builder.setView(rootView)
|
||||
.setPositiveButton(android.R.string.ok, (dialog, id) -> { });
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
private String androidNameFromApiNumber(int apiNumber) {
|
||||
return androidNameFromApiNumber(apiNumber, "");
|
||||
}
|
||||
|
||||
private String androidNameFromApiNumber(int apiNumber, String releaseVersion) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
Field[] fields = Build.VERSION_CODES.class.getFields();
|
||||
String apiName = "";
|
||||
for (Field field : fields) {
|
||||
String fieldName = field.getName();
|
||||
int fieldValue = -1;
|
||||
try {
|
||||
fieldValue = field.getInt(new Object());
|
||||
} catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NullPointerException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (fieldValue == apiNumber) {
|
||||
apiName = fieldName;
|
||||
}
|
||||
}
|
||||
if (apiName.isEmpty()) {
|
||||
String[] mapper = new String[]{
|
||||
"ANDROID BASE", "ANDROID BASE 1.1", "CUPCAKE", "DONUT",
|
||||
"ECLAIR", "ECLAIR_0_1", "ECLAIR_MR1", "FROYO",
|
||||
"GINGERBREAD", "GINGERBREAD_MR1", "HONEYCOMB", "HONEYCOMB_MR1",
|
||||
"HONEYCOMB_MR2", "ICE_CREAM_SANDWICH", "ICE_CREAM_SANDWICH_MR1", "JELLY_BEAN",
|
||||
"JELLY_BEAN", "JELLY_BEAN", "KITKAT", "KITKAT",
|
||||
"LOLLIPOOP", "LOLLIPOOP_MR1", "MARSHMALLOW", "NOUGAT",
|
||||
"NOUGAT", "OREO", "OREO"};
|
||||
int index = apiNumber - 1;
|
||||
apiName = index < mapper.length ? mapper[index] : "UNKNOWN_VERSION";
|
||||
}
|
||||
if (releaseVersion.isEmpty()) {
|
||||
String[] versions = new String[]{
|
||||
"1.0", "1.1", "1.5", "1.6",
|
||||
"2.0", "2.0.1", "2.1", "2.2.X",
|
||||
"2.3", "2.3.3", "3.0", "3.1",
|
||||
"3.2.0", "4.0.1", "4.0.3", "4.1.0",
|
||||
"4.2.0", "4.3.0", "4.4", "4.4",
|
||||
"5.0", "5.1", "6.0", "7.0",
|
||||
"7.1", "8.0.0", "8.1.0"};
|
||||
int index = apiNumber - 1;
|
||||
releaseVersion = index < versions.length ? versions[index] : "UNKNOWN_VERSION";
|
||||
}
|
||||
|
||||
builder.append("\n\t");
|
||||
if (!apiName.isEmpty())
|
||||
builder.append(apiName).append(" ");
|
||||
if (!releaseVersion.isEmpty())
|
||||
builder.append(releaseVersion).append(" ");
|
||||
builder.append("(API ").append(apiNumber).append(")");
|
||||
builder.append("\n");
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* KeePass DX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.dialogs;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.text.Html;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.kunzisoft.keepass.BuildConfig;
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.kunzisoft.keepass.utils.Util;
|
||||
|
||||
/**
|
||||
* Custom Dialog that asks the user to download the pro version or make a donation.
|
||||
*/
|
||||
public class UnderDevelopmentFeatureDialogFragment extends DialogFragment {
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
// Use the Builder class for convenient dialog construction
|
||||
assert getActivity() != null;
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
|
||||
SpannableStringBuilder stringBuilder = new SpannableStringBuilder();
|
||||
if (BuildConfig.CLOSED_STORE) {
|
||||
if (BuildConfig.FULL_VERSION) {
|
||||
stringBuilder.append(Html.fromHtml(getString(R.string.html_text_dev_feature_thanks))).append("\n\n")
|
||||
.append(Html.fromHtml(getString(R.string.html_rose))).append("\n\n")
|
||||
.append(Html.fromHtml(getString(R.string.html_text_dev_feature_work_hard))).append("\n")
|
||||
.append(Html.fromHtml(getString(R.string.html_text_dev_feature_upgrade))).append(" ");
|
||||
builder.setPositiveButton(android.R.string.ok, (dialog, id) -> dismiss());
|
||||
} else {
|
||||
stringBuilder.append(Html.fromHtml(getString(R.string.html_text_dev_feature))).append("\n\n")
|
||||
.append(Html.fromHtml(getString(R.string.html_text_dev_feature_buy_pro))).append("\n")
|
||||
.append(Html.fromHtml(getString(R.string.html_text_dev_feature_encourage)));
|
||||
builder.setPositiveButton(R.string.download, (dialog, id) -> {
|
||||
try {
|
||||
Util.gotoUrl(getContext(), R.string.app_pro_url);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Toast.makeText(getContext(), R.string.error_failed_to_launch_link, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(android.R.string.cancel, (dialog, id) -> dismiss());
|
||||
}
|
||||
}
|
||||
else {
|
||||
stringBuilder.append(Html.fromHtml(getString(R.string.html_text_dev_feature))).append("\n\n")
|
||||
.append(Html.fromHtml(getString(R.string.html_text_dev_feature_contibute))).append(" ")
|
||||
.append(Html.fromHtml(getString(R.string.html_text_dev_feature_encourage)));
|
||||
builder.setPositiveButton(R.string.contribute, (dialog, id) -> {
|
||||
try {
|
||||
Util.gotoUrl(getContext(), R.string.contribution_url);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Toast.makeText(getContext(), R.string.error_failed_to_launch_link, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(android.R.string.cancel, (dialog, id) -> dismiss());
|
||||
}
|
||||
builder.setMessage(stringBuilder);
|
||||
// Create the AlertDialog object and return it
|
||||
return builder.create();
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* KeePass DX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.dialogs;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
|
||||
public class WarningDialog extends AlertDialog {
|
||||
|
||||
protected String warning;
|
||||
private int showKey;
|
||||
|
||||
public WarningDialog(Context context, int dontShowKey) {
|
||||
super(context);
|
||||
|
||||
this.showKey = dontShowKey;
|
||||
}
|
||||
|
||||
public WarningDialog(Context context, int warningKey, int dontShowKey) {
|
||||
this(context, dontShowKey);
|
||||
|
||||
warning = context.getString(warningKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
Context ctx = getContext();
|
||||
setMessage(warning);
|
||||
|
||||
setButton(AlertDialog.BUTTON1, ctx.getText(android.R.string.ok), new DialogInterface.OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
|
||||
setButton(AlertDialog.BUTTON2, ctx.getText(R.string.beta_dontask), new DialogInterface.OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
Context ctx = getContext();
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
|
||||
SharedPreferences.Editor edit = prefs.edit();
|
||||
edit.putBoolean(ctx.getString(showKey), false);
|
||||
edit.commit();
|
||||
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -46,14 +46,14 @@ import com.kunzisoft.keepass.R;
|
||||
import com.kunzisoft.keepass.activities.ReadOnlyHelper;
|
||||
import com.kunzisoft.keepass.app.App;
|
||||
import com.kunzisoft.keepass.database.element.Database;
|
||||
import com.kunzisoft.keepass.dialogs.ProFeatureDialogFragment;
|
||||
import com.kunzisoft.keepass.dialogs.UnavailableFeatureDialogFragment;
|
||||
import com.kunzisoft.keepass.dialogs.UnderDevelopmentFeatureDialogFragment;
|
||||
import com.kunzisoft.keepass.activities.dialogs.ProFeatureDialogFragment;
|
||||
import com.kunzisoft.keepass.activities.dialogs.UnavailableFeatureDialogFragment;
|
||||
import com.kunzisoft.keepass.activities.dialogs.UnderDevelopmentFeatureDialogFragment;
|
||||
import com.kunzisoft.keepass.education.Education;
|
||||
import com.kunzisoft.keepass.fileselect.database.FileDatabaseHistory;
|
||||
import com.kunzisoft.keepass.fingerprint.FingerPrintHelper;
|
||||
import com.kunzisoft.keepass.icons.IconPackChooser;
|
||||
import com.kunzisoft.keepass.dialogs.KeyboardExplanationDialogFragment;
|
||||
import com.kunzisoft.keepass.activities.dialogs.KeyboardExplanationDialogFragment;
|
||||
import com.kunzisoft.keepass.settings.preferencedialogfragment.DatabaseDescriptionPreferenceDialogFragmentCompat;
|
||||
import com.kunzisoft.keepass.settings.preferencedialogfragment.DatabaseEncryptionAlgorithmPreferenceDialogFragmentCompat;
|
||||
import com.kunzisoft.keepass.settings.preferencedialogfragment.DatabaseKeyDerivationPreferenceDialogFragmentCompat;
|
||||
@@ -194,7 +194,7 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat
|
||||
FragmentManager fragmentManager = getFragmentManager();
|
||||
assert fragmentManager != null;
|
||||
((SwitchPreference) preference).setChecked(false);
|
||||
UnavailableFeatureDialogFragment.getInstance(Build.VERSION_CODES.M)
|
||||
UnavailableFeatureDialogFragment.Companion.getInstance(Build.VERSION_CODES.M)
|
||||
.show(getFragmentManager(), "unavailableFeatureDialog");
|
||||
return false;
|
||||
});
|
||||
@@ -297,7 +297,7 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat
|
||||
((SwitchPreference) preference).setChecked(false);
|
||||
FragmentManager fragmentManager = getFragmentManager();
|
||||
assert fragmentManager != null;
|
||||
UnavailableFeatureDialogFragment.getInstance(Build.VERSION_CODES.O)
|
||||
UnavailableFeatureDialogFragment.Companion.getInstance(Build.VERSION_CODES.O)
|
||||
.show(fragmentManager, "unavailableFeatureDialog");
|
||||
return false;
|
||||
});
|
||||
|
||||
@@ -64,7 +64,8 @@
|
||||
android:fillViewport="true"
|
||||
android:scrollbarStyle="insideOverlay">
|
||||
|
||||
<com.kunzisoft.keepass.view.EntryContentsView android:id="@+id/entry_contents"
|
||||
<com.kunzisoft.keepass.activities.view.EntryContentsView
|
||||
android:id="@+id/entry_contents"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent" />
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@
|
||||
android:background="?android:attr/windowBackground" />
|
||||
</LinearLayout>
|
||||
|
||||
<com.kunzisoft.keepass.view.AddNodeButtonView
|
||||
<com.kunzisoft.keepass.activities.view.AddNodeButtonView
|
||||
android:id="@+id/add_node_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
Reference in New Issue
Block a user