package sushi.hardcore.aira import android.content.* import android.graphics.drawable.Drawable import android.os.Bundle import android.os.IBinder import android.view.MenuItem import android.view.View import android.widget.EditText import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat import androidx.preference.SwitchPreferenceCompat import com.bumptech.glide.Glide import com.bumptech.glide.RequestBuilder import com.bumptech.glide.request.RequestOptions import com.bumptech.glide.request.target.CustomTarget import com.bumptech.glide.request.transition.Transition import sushi.hardcore.aira.background_service.AIRAService import sushi.hardcore.aira.databinding.ActivitySettingsBinding import sushi.hardcore.aira.databinding.ChangeAvatarDialogBinding import sushi.hardcore.aira.databinding.DialogEditTextBinding import sushi.hardcore.aira.utils.AvatarPicker import sushi.hardcore.aira.utils.StringUtils class SettingsActivity: AppCompatActivity() { class MySettingsFragment(private val activity: AppCompatActivity): PreferenceFragmentCompat() { private lateinit var databaseFolder: String private lateinit var airaService: AIRAService private val avatarPicker = AvatarPicker(activity) { avatar -> if (::airaService.isInitialized) { airaService.changeAvatar(avatar) } displayAvatar(avatar) } private lateinit var identityAvatarPreference: Preference private lateinit var startAtBootSwitch: SwitchPreferenceCompat override fun onAttach(context: Context) { super.onAttach(context) avatarPicker.register() } override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { setPreferencesFromResource(R.xml.preferences, rootKey) databaseFolder = Constants.getDatabaseFolder(activity) findPreference("identityAvatar")?.let { identityAvatarPreference = it } startAtBootSwitch = findPreference("startAtBoot")!! updateStartAtBootSwitch(AIRADatabase.isIdentityProtected(databaseFolder)) val paddingPreference = findPreference("psecPadding") paddingPreference?.isPersistent = false AIRADatabase.getIdentityAvatar(databaseFolder)?.let { avatar -> displayAvatar(avatar) } Intent(activity, AIRAService::class.java).also { serviceIntent -> activity.bindService(serviceIntent, object : ServiceConnection { override fun onServiceConnected(name: ComponentName?, service: IBinder) { val binder = service as AIRAService.AIRABinder airaService = binder.getService() paddingPreference?.isChecked = airaService.usePadding } override fun onServiceDisconnected(name: ComponentName?) {} }, Context.BIND_AUTO_CREATE) } identityAvatarPreference.setOnPreferenceClickListener { val dialogBuilder = AlertDialog.Builder(activity, R.style.CustomAlertDialog) .setTitle(R.string.your_avatar) .setPositiveButton(R.string.set_a_new_one) { _, _ -> avatarPicker.launch() } val dialogBinding = ChangeAvatarDialogBinding.inflate(layoutInflater) val avatar = AIRADatabase.getIdentityAvatar(databaseFolder) if (avatar == null) { dialogBinding.avatar.setTextAvatar(airaService.identityName) } else { dialogBinding.avatar.setImageAvatar(avatar) dialogBuilder.setNegativeButton(R.string.remove) { _, _ -> displayAvatar(null) airaService.changeAvatar(null) } } dialogBuilder.setView(dialogBinding.root).show() false } findPreference("identityName")?.setOnPreferenceClickListener { val dialogBinding = DialogEditTextBinding.inflate(layoutInflater) dialogBinding.editText.setText(airaService.identityName) AlertDialog.Builder(activity, R.style.CustomAlertDialog) .setTitle(it.title) .setView(dialogBinding.root) .setPositiveButton(R.string.ok) { _, _ -> airaService.changeName(dialogBinding.editText.text.toString()) } .setNegativeButton(R.string.cancel, null) .show() false } findPreference("deleteIdentity")?.setOnPreferenceClickListener { AlertDialog.Builder(activity, R.style.CustomAlertDialog) .setMessage(R.string.confirm_delete) .setTitle(R.string.warning) .setPositiveButton(R.string.ok) { _, _ -> if (Constants.getDatabasePath(activity).delete()) { airaService.logOut() startActivity(Intent(activity, LoginActivity::class.java)) activity.finish() } } .setNegativeButton(R.string.cancel, null) .show() false } findPreference("identityPassword")?.setOnPreferenceClickListener { val dialogView = layoutInflater.inflate(R.layout.dialog_password, null) val oldPasswordEditText = dialogView.findViewById(R.id.old_password) val isIdentityProtected = AIRADatabase.isIdentityProtected(databaseFolder) if (!isIdentityProtected) { oldPasswordEditText.visibility = View.GONE } val newPasswordEditText = dialogView.findViewById(R.id.new_password) val newPasswordConfirmEditText = dialogView.findViewById(R.id.new_password_confirm) AlertDialog.Builder(activity, R.style.CustomAlertDialog) .setView(dialogView) .setTitle(R.string.change_password) .setPositiveButton(R.string.ok) { _, _ -> val newPassword = newPasswordEditText.text.toString().toByteArray() val newPasswordConfirm = newPasswordConfirmEditText.text.toString().toByteArray() if (newPassword.contentEquals(newPasswordConfirm)) { if (newPassword.isEmpty()) { if (isIdentityProtected) { //don't change password if identity is not protected and new password is blank changePassword(isIdentityProtected, oldPasswordEditText, null) } } else { changePassword(isIdentityProtected, oldPasswordEditText, newPassword) } } else { AlertDialog.Builder(activity, R.style.CustomAlertDialog) .setMessage(R.string.password_mismatch) .setTitle(R.string.error) .setPositiveButton(R.string.ok, null) .show() } newPassword.fill(0) newPasswordConfirm.fill(0) } .setNegativeButton(R.string.cancel, null) .show() false } findPreference("fingerprint")?.let { fingerprintPreference -> val fingerprint = StringUtils.beautifyFingerprint(AIRADatabase.getIdentityFingerprint()) fingerprintPreference.summary = fingerprint fingerprintPreference.setOnPreferenceClickListener { activity.getSystemService(CLIPBOARD_SERVICE)?.let { service -> val clipboardManager = service as ClipboardManager clipboardManager.setPrimaryClip(ClipData.newPlainText("", fingerprint)) } Toast.makeText(activity, R.string.copied, Toast.LENGTH_SHORT).show() false } } paddingPreference?.setOnPreferenceChangeListener { _, checked -> airaService.usePadding = checked as Boolean AIRADatabase.setUsePadding(checked) true } } private fun displayAvatar(avatar: ByteArray?) { if (avatar == null) { identityAvatarPreference.setIcon(R.drawable.ic_face) } else { Glide .with(this) .load(avatar) .apply(RequestOptions().override(90)) //reduce image to be the same size as other icons .circleCrop() .into(object : CustomTarget() { override fun onResourceReady(resource: Drawable, transition: Transition?) { identityAvatarPreference.icon = resource } override fun onLoadCleared(placeholder: Drawable?) {} }) } } private fun changePassword(isIdentityProtected: Boolean, oldPasswordEditText: EditText, newPassword: ByteArray?) { val oldPassword = if (isIdentityProtected) { oldPasswordEditText.text.toString().toByteArray() } else { null } if (AIRADatabase.changePassword(databaseFolder, oldPassword, newPassword)) { val isNowIdentityProtected = newPassword != null updateStartAtBootSwitch(isNowIdentityProtected) if (isIdentityProtected && !isNowIdentityProtected ) { startAtBootSwitch.isChecked = true } } else { AlertDialog.Builder(activity, R.style.CustomAlertDialog) .setMessage(R.string.change_password_failed) .setTitle(R.string.error) .setPositiveButton(R.string.ok, null) .show() } oldPassword?.fill(0) } private fun updateStartAtBootSwitch(isIdentityProtected: Boolean) { startAtBootSwitch.isEnabled = !isIdentityProtected startAtBootSwitch.summary = getString(if (isIdentityProtected) { R.string.start_at_boot_summary_identity_protected } else { R.string.start_at_boot_summary }) } } override fun onOptionsItemSelected(item: MenuItem): Boolean { return if (item.itemId == android.R.id.home) { finish() true } else { super.onOptionsItemSelected(item) } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val binding = ActivitySettingsBinding.inflate(layoutInflater) setContentView(binding.root) supportFragmentManager .beginTransaction() .replace(R.id.settings_container, MySettingsFragment(this)) .commit() supportActionBar?.setDisplayHomeAsUpEnabled(true) } }