Password generator implemented
- Passwords also get's checked if it's compromised
@@ -41,6 +41,9 @@ dependencies {
|
|||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||||
implementation 'androidx.core:core-ktx:1.3.0'
|
implementation 'androidx.core:core-ktx:1.3.0'
|
||||||
|
|
||||||
|
/* Password strengh library */
|
||||||
|
compile 'com.nulab-inc:zxcvbn:1.3.0'
|
||||||
|
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7"
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7"
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7"
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7"
|
||||||
|
|
||||||
|
|||||||
@@ -27,12 +27,16 @@ import com.google.zxing.BarcodeFormat
|
|||||||
import com.google.zxing.integration.android.IntentIntegrator
|
import com.google.zxing.integration.android.IntentIntegrator
|
||||||
import com.google.zxing.integration.android.IntentResult
|
import com.google.zxing.integration.android.IntentResult
|
||||||
import com.journeyapps.barcodescanner.BarcodeEncoder
|
import com.journeyapps.barcodescanner.BarcodeEncoder
|
||||||
|
import com.nulabinc.zxcvbn.Zxcvbn
|
||||||
import dev.turingcomplete.kotlinonetimepassword.GoogleAuthenticator
|
import dev.turingcomplete.kotlinonetimepassword.GoogleAuthenticator
|
||||||
import kotlinx.android.synthetic.main.activity_create.*
|
import kotlinx.android.synthetic.main.activity_create.*
|
||||||
|
import kotlinx.android.synthetic.main.activity_generator.*
|
||||||
|
import kotlinx.android.synthetic.main.activity_generator.view.*
|
||||||
import kotlinx.android.synthetic.main.dialogpassphrase.view.*
|
import kotlinx.android.synthetic.main.dialogpassphrase.view.*
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.lang.IllegalArgumentException
|
import java.lang.IllegalArgumentException
|
||||||
|
import java.lang.StringBuilder
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
@@ -168,54 +172,70 @@ class CreateActivity : AppCompatActivity() {
|
|||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
print_button.setOnClickListener {
|
print_button.setOnClickListener {
|
||||||
// Ask user for passhprase and hint
|
fun continueAfterCheck() {
|
||||||
val builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.PassphraseDialog))
|
// Ask user for passhprase and hint
|
||||||
|
val builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.PassphraseDialog))
|
||||||
|
|
||||||
with(builder) {
|
with(builder) {
|
||||||
val editTextLayout = layoutInflater.inflate(R.layout.dialogpassphrase, null)
|
val editTextLayout = layoutInflater.inflate(R.layout.dialogpassphrase, null)
|
||||||
setView(editTextLayout)
|
setView(editTextLayout)
|
||||||
setTitle("Set Passphrase")
|
setTitle("Set Passphrase")
|
||||||
setMessage("Final step is it to set your passphrase. Minimum are 8 characters.")
|
setMessage("Final step is it to set your passphrase. Minimum are 8 characters.")
|
||||||
setPositiveButton("Print", DialogInterface.OnClickListener { dialogInterface, i ->
|
setPositiveButton("Print", DialogInterface.OnClickListener { dialogInterface, i ->
|
||||||
val passphrase = editTextLayout.passphrase_input.text.toString();
|
val passphrase = editTextLayout.passphrase_input.text.toString();
|
||||||
if (passphrase == "") {
|
if (passphrase == "") {
|
||||||
// Make a new alert, telling the user that passphrase must not be null.
|
// Make a new alert, telling the user that passphrase must not be null.
|
||||||
dialogInterface.cancel()
|
dialogInterface.cancel()
|
||||||
showError("Empty passphrase", "Passphrase must not be null.")
|
showError("Empty passphrase", "Passphrase must not be null.")
|
||||||
return@OnClickListener
|
return@OnClickListener
|
||||||
}
|
}
|
||||||
if (passphrase.length < 8) {
|
if (passphrase.length < 8) {
|
||||||
// Make a new alert, telling the user that his passphrase doesn't meet the minimum.
|
// Make a new alert, telling the user that his passphrase doesn't meet the minimum.
|
||||||
dialogInterface.cancel()
|
dialogInterface.cancel()
|
||||||
showError("Weak passphrase", "Passphrase has to be at least 8 characters long.")
|
showError("Weak passphrase", "Passphrase has to be at least 8 characters long.")
|
||||||
return@OnClickListener
|
return@OnClickListener
|
||||||
}
|
}
|
||||||
if (passphrase != editTextLayout.passphrase2_input.text.toString()) {
|
if (passphrase != editTextLayout.passphrase2_input.text.toString()) {
|
||||||
// Make a new alert, telling the user that his passphrase doesn't match the repeat field.
|
// Make a new alert, telling the user that his passphrase doesn't match the repeat field.
|
||||||
dialogInterface.cancel()
|
dialogInterface.cancel()
|
||||||
showError("Passphrase mismatch", "Both passphrases do not match.")
|
showError("Passphrase mismatch", "Both passphrases do not match.")
|
||||||
return@OnClickListener
|
return@OnClickListener
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if password is found in our offline password list
|
// Check if password is found in our offline password list
|
||||||
if(passwordKnown(passphrase)) {
|
if(passwordKnown(passphrase)) {
|
||||||
// Make a new alert, telling the user that his passphrase was found in our local wordlist.
|
// Make a new alert, telling the user that his passphrase was found in our local wordlist.
|
||||||
dialogInterface.cancel()
|
dialogInterface.cancel()
|
||||||
showError("Passphrase is compromised!", "Passphrase got found in a wordlist of bad passwords. " +
|
showError("Passphrase is compromised!", "Passphrase got found in a wordlist of bad passwords. " +
|
||||||
"If you already used it somewhere, change it immediately!")
|
"If you already used it somewhere, change it immediately!")
|
||||||
return@OnClickListener
|
return@OnClickListener
|
||||||
}
|
}
|
||||||
|
|
||||||
doPrint(editTextLayout.passphrase_input.text.toString(),
|
doPrint(editTextLayout.passphrase_input.text.toString(),
|
||||||
editTextLayout.hint_input.text.toString())
|
editTextLayout.hint_input.text.toString())
|
||||||
})
|
})
|
||||||
setNegativeButton("Go back", DialogInterface.OnClickListener { dialogInterface, i ->
|
setNegativeButton("Go back", DialogInterface.OnClickListener { dialogInterface, i ->
|
||||||
dialogInterface.dismiss()
|
dialogInterface.dismiss()
|
||||||
})
|
})
|
||||||
show()
|
show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// First check if entered password is compromised
|
||||||
|
if (passwordKnown(password_input.text.toString())) {
|
||||||
|
val builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.ErrorDialog))
|
||||||
|
|
||||||
|
with(builder) {
|
||||||
|
setTitle("Password compromised!")
|
||||||
|
setMessage("Your password is weak and should be changed as it got found in a list of weak passwords.")
|
||||||
|
setPositiveButton("I'll change it", DialogInterface.OnClickListener { dialogInterface, i ->
|
||||||
|
})
|
||||||
|
setNegativeButton("I don't care", DialogInterface.OnClickListener { dialogInterface, i ->
|
||||||
|
continueAfterCheck()
|
||||||
|
})
|
||||||
|
show()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
password_hide.setOnClickListener {
|
password_hide.setOnClickListener {
|
||||||
if (password_input.transformationMethod == HideReturnsTransformationMethod.getInstance()) {
|
if (password_input.transformationMethod == HideReturnsTransformationMethod.getInstance()) {
|
||||||
@@ -227,6 +247,121 @@ class CreateActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
password_random.setOnClickListener {
|
||||||
|
val builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.PassphraseGenerator))
|
||||||
|
|
||||||
|
with (builder) {
|
||||||
|
val layout = layoutInflater.inflate(R.layout.activity_generator, null)
|
||||||
|
val zxcvbn = Zxcvbn()
|
||||||
|
var length: Int = 8
|
||||||
|
setTitle("Generate password")
|
||||||
|
setView(layout)
|
||||||
|
|
||||||
|
fun newPassword() {
|
||||||
|
var combined = ""
|
||||||
|
val upper_case = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
val lower_case = "abcdefghijklmnopqrstuvwxyz"
|
||||||
|
val speicals = "!\";#$%&'()*+,-./:;<=>?@[/]^_`"
|
||||||
|
val digits = "1234567890"
|
||||||
|
val emojis = arrayOf(0x1F600, 0x1F603, 0x1F601, 0x1F911, 0x1F910, 0x1F637, 0x1F47D, 0x1F480, 0x1F916)
|
||||||
|
val rand: Random = Random()
|
||||||
|
|
||||||
|
if (layout.AZ.isChecked) combined += upper_case
|
||||||
|
if (layout.az.isChecked) combined += lower_case
|
||||||
|
if (layout.zero_nine.isChecked) combined += digits
|
||||||
|
if (layout.emojis.isChecked) {
|
||||||
|
emojis.forEach {
|
||||||
|
combined += String(Character.toChars(it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (layout.special.isChecked) combined += speicals
|
||||||
|
|
||||||
|
val sb: StringBuilder = StringBuilder(length)
|
||||||
|
for (x in 1..length) {
|
||||||
|
sb.append(combined[rand.nextInt(combined.length)])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adapt text size
|
||||||
|
if (sb.length > 10) {
|
||||||
|
layout.random_string.textSize = 24.0f
|
||||||
|
} else if (sb.length > 16) {
|
||||||
|
layout.random_string.textSize = 18.0f
|
||||||
|
}
|
||||||
|
|
||||||
|
// Measure strengh
|
||||||
|
layout.progressBar.progress = zxcvbn.measure(sb.toString())
|
||||||
|
.score
|
||||||
|
|
||||||
|
if (layout.progressBar.progress == 1) {
|
||||||
|
layout.progressBar.progressTintList = ColorStateList.valueOf(Color.RED)
|
||||||
|
} else if (layout.progressBar.progress == 2) {
|
||||||
|
layout.progressBar.progressTintList = ColorStateList.valueOf(Color.YELLOW)
|
||||||
|
} else if (layout.progressBar.progress == 3) {
|
||||||
|
layout.progressBar.progressTintList = ColorStateList.valueOf(Color.GREEN)
|
||||||
|
} else {
|
||||||
|
layout.progressBar.progressTintList = ColorStateList.valueOf(Color.GREEN)
|
||||||
|
}
|
||||||
|
|
||||||
|
layout.random_string.setText(sb.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initial set
|
||||||
|
layout.length_label.setText(length.toString())
|
||||||
|
newPassword()
|
||||||
|
|
||||||
|
// Add length
|
||||||
|
layout.add_button.setOnClickListener {
|
||||||
|
length++
|
||||||
|
layout.length_label.setText(length.toString())
|
||||||
|
newPassword()
|
||||||
|
}
|
||||||
|
layout.add_button.setOnLongClickListener {
|
||||||
|
length += 10
|
||||||
|
layout.length_label.setText(length.toString())
|
||||||
|
newPassword()
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subtract length
|
||||||
|
layout.subtract_button.setOnClickListener {
|
||||||
|
length--
|
||||||
|
layout.length_label.setText(length.toString())
|
||||||
|
newPassword()
|
||||||
|
}
|
||||||
|
layout.subtract_button.setOnLongClickListener {
|
||||||
|
length -= 10
|
||||||
|
layout.length_label.setText(length.toString())
|
||||||
|
newPassword()
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh
|
||||||
|
layout.refresh_button.setOnClickListener {
|
||||||
|
newPassword()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy password
|
||||||
|
layout.copy_button.setOnClickListener {
|
||||||
|
// Copy code if already scanend
|
||||||
|
val clip: ClipboardManager = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||||
|
clip.setPrimaryClip(ClipData.newPlainText("Random password", layout.random_string.text.toString()))
|
||||||
|
Toast.makeText(applicationContext, "Copied!", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
setPositiveButton("Use this",
|
||||||
|
DialogInterface.OnClickListener { dialog, id ->
|
||||||
|
password_input.setText(layout.random_string.text)
|
||||||
|
})
|
||||||
|
setNegativeButton("Go back",
|
||||||
|
DialogInterface.OnClickListener { dialog, id ->
|
||||||
|
dialog.dismiss()
|
||||||
|
})
|
||||||
|
show()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
fa_input.isFocusable = false
|
fa_input.isFocusable = false
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,27 @@ package com.github.mondei1.offpass
|
|||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
|
import kotlinx.android.synthetic.main.activity_generator.*
|
||||||
|
|
||||||
class GeneratorActivity : AppCompatActivity() {
|
class GeneratorActivity : AppCompatActivity() {
|
||||||
|
var length: Int = 12
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.activity_generator)
|
setContentView(R.layout.activity_generator)
|
||||||
|
|
||||||
|
length_label.setText(length.toString())
|
||||||
|
Log.i("Generator", "Length: $length")
|
||||||
|
add_button.setOnClickListener {
|
||||||
|
Log.i("Generator", "Length: $length")
|
||||||
|
length++
|
||||||
|
length_label.setText(length.toString())
|
||||||
|
}
|
||||||
|
subtract_button.setOnClickListener {
|
||||||
|
Log.i("Generator", "Length: $length")
|
||||||
|
length--
|
||||||
|
length_label.setText(length.toString())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BIN
app/src/main/res/drawable-hdpi/ic_add.png
Normal file
|
After Width: | Height: | Size: 1011 B |
BIN
app/src/main/res/drawable-hdpi/ic_content_copy.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
app/src/main/res/drawable-hdpi/ic_refresh.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
app/src/main/res/drawable-hdpi/ic_remove.png
Normal file
|
After Width: | Height: | Size: 526 B |
BIN
app/src/main/res/drawable-mdpi/ic_add.png
Normal file
|
After Width: | Height: | Size: 395 B |
BIN
app/src/main/res/drawable-mdpi/ic_content_copy.png
Normal file
|
After Width: | Height: | Size: 914 B |
BIN
app/src/main/res/drawable-mdpi/ic_refresh.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
app/src/main/res/drawable-mdpi/ic_remove.png
Normal file
|
After Width: | Height: | Size: 233 B |
BIN
app/src/main/res/drawable-xhdpi/ic_add.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
app/src/main/res/drawable-xhdpi/ic_content_copy.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
app/src/main/res/drawable-xhdpi/ic_refresh.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
app/src/main/res/drawable-xhdpi/ic_remove.png
Normal file
|
After Width: | Height: | Size: 664 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_add.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
app/src/main/res/drawable-xxhdpi/ic_content_copy.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
app/src/main/res/drawable-xxhdpi/ic_refresh.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
app/src/main/res/drawable-xxhdpi/ic_remove.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/ic_add.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/ic_content_copy.png
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/ic_refresh.png
Normal file
|
After Width: | Height: | Size: 8.3 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/ic_remove.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
@@ -1,9 +1,171 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
tools:context=".GeneratorActivity">
|
tools:context=".GeneratorActivity">
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="350dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progressBar"
|
||||||
|
style="?android:attr/progressBarStyleHorizontal"
|
||||||
|
android:layout_width="256dp"
|
||||||
|
android:layout_height="10dp"
|
||||||
|
android:layout_marginStart="80dp"
|
||||||
|
android:layout_marginTop="100dp"
|
||||||
|
android:layout_marginEnd="80dp"
|
||||||
|
android:progress="2"
|
||||||
|
android:min="0"
|
||||||
|
android:max="4"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/random_string"
|
||||||
|
android:layout_width="201dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="80dp"
|
||||||
|
android:layout_marginEnd="80dp"
|
||||||
|
android:layout_marginBottom="10dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:text="D%g$MA0H8d"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
|
android:textSize="30sp"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/progressBar"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/refresh_button"
|
||||||
|
android:layout_width="32dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:background="#00FFFFFF"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/progressBar"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/random_string"
|
||||||
|
app:srcCompat="@drawable/ic_refresh" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/copy_button"
|
||||||
|
android:layout_width="32dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:background="#00FFFFFF"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/progressBar"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/random_string"
|
||||||
|
app:srcCompat="@drawable/ic_content_copy" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/password_length_container"
|
||||||
|
android:layout_width="142dp"
|
||||||
|
android:layout_height="45dp"
|
||||||
|
android:layout_marginStart="1dp"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:layout_marginEnd="1dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0.498"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/progressBar">
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/subtract_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="7dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="#00FFFFFF"
|
||||||
|
app:srcCompat="@drawable/ic_remove" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/length_label"
|
||||||
|
android:layout_width="45dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:fontFamily="sans-serif-light"
|
||||||
|
android:gravity="center_horizontal|center_vertical"
|
||||||
|
android:text="0"
|
||||||
|
android:textColor="@color/colorPrimaryDark"
|
||||||
|
android:textSize="24sp" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/add_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="7dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="#00FFFFFF"
|
||||||
|
app:srcCompat="@drawable/ic_add" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<CheckBox
|
||||||
|
android:id="@+id/AZ"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="32dp"
|
||||||
|
android:layout_marginTop="32dp"
|
||||||
|
android:checked="true"
|
||||||
|
android:text="A-Z"
|
||||||
|
android:textSize="20sp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/password_length_container" />
|
||||||
|
|
||||||
|
<CheckBox
|
||||||
|
android:id="@+id/az"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="32dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:checked="true"
|
||||||
|
android:text="a-z"
|
||||||
|
android:textSize="20sp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/AZ" />
|
||||||
|
|
||||||
|
<CheckBox
|
||||||
|
android:id="@+id/zero_nine"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="32dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:checked="true"
|
||||||
|
android:text="0-9"
|
||||||
|
android:textSize="20sp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/az" />
|
||||||
|
|
||||||
|
<CheckBox
|
||||||
|
android:id="@+id/special"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="32dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:checked="true"
|
||||||
|
android:text="!"#$%'()*+"
|
||||||
|
android:textSize="20sp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/zero_nine" />
|
||||||
|
|
||||||
|
<CheckBox
|
||||||
|
android:id="@+id/emojis"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="32dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:text="😃👽😺👋"
|
||||||
|
android:textSize="20sp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/special" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</LinearLayout>
|
||||||
@@ -22,7 +22,9 @@
|
|||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/back"
|
android:id="@+id/back"
|
||||||
|
|||||||
@@ -19,4 +19,11 @@
|
|||||||
<item name="android:textStyle">bold</item>
|
<item name="android:textStyle">bold</item>
|
||||||
<item name="android:background">@android:color/holo_red_light</item>
|
<item name="android:background">@android:color/holo_red_light</item>
|
||||||
</style>
|
</style>
|
||||||
|
<style name="PassphraseGenerator" parent="@android:style/Theme.Material.Dialog">
|
||||||
|
<item name="android:paddingTop">0dp</item>
|
||||||
|
<item name="android:layout_marginTop">0dp</item>
|
||||||
|
<item name="android:textColor">@color/colorPrimaryDark</item>
|
||||||
|
<item name="background">@color/colorPrimary</item>
|
||||||
|
<item name="android:textStyle">bold</item>
|
||||||
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||