diff --git a/pretixprint/app/build.gradle b/pretixprint/app/build.gradle index 8cce85f1..8584d763 100644 --- a/pretixprint/app/build.gradle +++ b/pretixprint/app/build.gradle @@ -110,7 +110,6 @@ dependencies { implementation 'androidx.multidex:multidex:2.0.1' implementation 'com.tom_roush:pdfbox-android:1.8.10.0' implementation "androidx.viewpager2:viewpager2:1.0.0" - implementation 'com.andrognito.pinlockview:pinlockview:2.1.0' // libpretixprint implementation 'com.github.librepdf:openpdf:1.3.24' diff --git a/pretixprint/app/src/main/assets/about.html b/pretixprint/app/src/main/assets/about.html index 31bfda93..b7718b9d 100644 --- a/pretixprint/app/src/main/assets/about.html +++ b/pretixprint/app/src/main/assets/about.html @@ -21,7 +21,7 @@ libpretixprint (c) rami.io GmbH – Apache License 2.0

cups4j (c) harwey – GNU Lesser General Public License 3

escpos-coffee (c) Michael Billington, Marco Antonio Anastacio Cintra – MIT License

-pinlockview (c) aritraroy – Apache License 2.0

+LolliPin (c) OrangeGangsters – MIT License

Fonts

Roboto, Christian Robertson, Apache License 2.0
Lato, Lukasz Dziedzic, SIL Open Font License
diff --git a/pretixprint/app/src/main/java/eu/pretix/pretixprint/ui/KeyboardButtonView.kt b/pretixprint/app/src/main/java/eu/pretix/pretixprint/ui/KeyboardButtonView.kt new file mode 100644 index 00000000..86d9843a --- /dev/null +++ b/pretixprint/app/src/main/java/eu/pretix/pretixprint/ui/KeyboardButtonView.kt @@ -0,0 +1,88 @@ +package eu.pretix.pretixprint.ui + +import android.content.Context +import android.os.Build +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.MotionEvent +import android.view.View +import android.widget.ImageView +import android.widget.RelativeLayout +import android.widget.TextView +import eu.pretix.pretixprint.R + + +// (c) 2015 OrangeGangsters +// MIT License +// https://github.com/omadahealth/LolliPin/blob/0c523dfb7e9ee5dfcf37ad047cbb970ccd8794fb/lib/src/main/java/com/github/omadahealth/lollipin/lib/views/KeyboardButtonView.java + +interface KeyboardButtonClickedListener { + +} + +class KeyboardButtonView @JvmOverloads constructor(private val mContext: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : RelativeLayout(mContext, attrs, defStyleAttr) { + + private var mKeyboardButtonClickedListener: KeyboardButtonClickedListener? = null + private var mRippleView: View? = null + + init { + initializeView(attrs, defStyleAttr) + } + + private fun initializeView(attrs: AttributeSet?, defStyleAttr: Int) { + if (attrs != null && !isInEditMode) { + val attributes = mContext.getTheme().obtainStyledAttributes(attrs, R.styleable.KeyboardButtonView, + defStyleAttr, 0) + val text = attributes.getString(R.styleable.KeyboardButtonView_lp_keyboard_button_text) + val image = attributes.getDrawable(R.styleable.KeyboardButtonView_lp_keyboard_button_image) + val rippleEnabled = attributes.getBoolean(R.styleable.KeyboardButtonView_lp_keyboard_button_ripple_enabled, true) + + attributes.recycle() + + val inflater = mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater + val view = inflater.inflate(R.layout.view_keyboard_button, this) as KeyboardButtonView + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + view.focusable = NOT_FOCUSABLE + } + + if (text != null) { + val textView = view.findViewById(R.id.keyboard_button_textview) as TextView + textView?.setText(text) + } + if (image != null) { + val imageView = view.findViewById(R.id.keyboard_button_imageview) as ImageView + if (imageView != null) { + imageView!!.setImageDrawable(image) + imageView!!.setVisibility(View.VISIBLE) + } + } + + mRippleView = view.findViewById(R.id.pin_code_keyboard_button_ripple) as View + //mRippleView!!.setRippleAnimationListener(this) + if (mRippleView != null) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + mRippleView!!.focusable = NOT_FOCUSABLE + } + if (!rippleEnabled) { + mRippleView!!.setVisibility(View.INVISIBLE) + } + } + } + } + + fun setOnRippleAnimationEndListener(keyboardButtonClickedListener: KeyboardButtonClickedListener) { + mKeyboardButtonClickedListener = keyboardButtonClickedListener + } + + fun onRippleAnimationEnd() { + if (mKeyboardButtonClickedListener != null) { + //mKeyboardButtonClickedListener!!.onRippleAnimationEnd() + } + } + + override fun onInterceptTouchEvent(event: MotionEvent): Boolean { + onTouchEvent(event) + return false + } +} diff --git a/pretixprint/app/src/main/java/eu/pretix/pretixprint/ui/PinDialog.kt b/pretixprint/app/src/main/java/eu/pretix/pretixprint/ui/PinDialog.kt new file mode 100644 index 00000000..4df83a49 --- /dev/null +++ b/pretixprint/app/src/main/java/eu/pretix/pretixprint/ui/PinDialog.kt @@ -0,0 +1,87 @@ +package eu.pretix.pretixprint.ui + +import android.app.Dialog +import android.app.DialogFragment +import android.os.Bundle +import android.view.KeyEvent +import android.view.View +import androidx.databinding.ObservableField +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import eu.pretix.pretixprint.databinding.DialogPinBinding +import java.util.Collections + + +class PINInputDataHolder() { + val input = ObservableField("") + val text = ObservableField("") +} + +interface ChecksPinFragment { + fun checkPin(pin: String) +} + +// PinDialog, backported for old android.app.DialogFragment (no androidx yet) +class PinDialog : DialogFragment() { + companion object { + const val TAG = "PinDialogFragment" + } + + val data = PINInputDataHolder() + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + data.input.set("") + + val binding = DialogPinBinding.inflate(parentFragment.layoutInflater) + binding.data = data + + binding.keyboardButtonView0.setOnClickListener { pushDigit("0") } + binding.keyboardButtonView00.visibility = View.INVISIBLE + binding.keyboardButtonView1.setOnClickListener { pushDigit("1") } + binding.keyboardButtonView2.setOnClickListener { pushDigit("2") } + binding.keyboardButtonView3.setOnClickListener { pushDigit("3") } + binding.keyboardButtonView4.setOnClickListener { pushDigit("4") } + binding.keyboardButtonView5.setOnClickListener { pushDigit("5") } + binding.keyboardButtonView6.setOnClickListener { pushDigit("6") } + binding.keyboardButtonView7.setOnClickListener { pushDigit("7") } + binding.keyboardButtonView8.setOnClickListener { pushDigit("8") } + binding.keyboardButtonView9.setOnClickListener { pushDigit("9") } + binding.keyboardButtonViewBackspace.setOnClickListener { pushBackspace() } + + return MaterialAlertDialogBuilder(context!!) + .setView(binding.root) + .setOnKeyListener { _, keyCode, event -> + if (event.action != KeyEvent.ACTION_DOWN) return@setOnKeyListener false + + if (event.displayLabel.toString().matches(Regex("^[0-9]$"))) { + pushDigit(event.displayLabel.toString()) + return@setOnKeyListener true + } + if (keyCode == KeyEvent.KEYCODE_DEL) { + pushBackspace() + return@setOnKeyListener true + } + if (keyCode == KeyEvent.KEYCODE_ESCAPE) { + dismiss() + return@setOnKeyListener true + } + + return@setOnKeyListener false + } + .create() + } + + protected fun pushBackspace() { + val current = data.input.get()!! + if (current.isNotBlank()) { + data.input.set(current.substring(0, current.length - 1)) + } + data.text.set(Collections.nCopies(data.input.get()!!.length, "*").joinToString("")) + } + + protected fun pushDigit(digit: String) { + val current = data.input.get()!! + data.input.set(current + digit) + data.text.set(Collections.nCopies(data.input.get()!!.length, "*").joinToString("")) + (parentFragment as ChecksPinFragment).checkPin(data.input.get()!!) + } +} \ No newline at end of file diff --git a/pretixprint/app/src/main/java/eu/pretix/pretixprint/ui/Settings.kt b/pretixprint/app/src/main/java/eu/pretix/pretixprint/ui/Settings.kt index 95f9f1ee..e2c5aedb 100644 --- a/pretixprint/app/src/main/java/eu/pretix/pretixprint/ui/Settings.kt +++ b/pretixprint/app/src/main/java/eu/pretix/pretixprint/ui/Settings.kt @@ -13,23 +13,19 @@ import android.view.LayoutInflater import android.webkit.WebView import androidx.annotation.StringRes import androidx.appcompat.app.AlertDialog -import com.andrognito.pinlockview.IndicatorDots -import com.andrognito.pinlockview.PinLockListener -import com.andrognito.pinlockview.PinLockView -import com.google.android.material.dialog.MaterialAlertDialogBuilder import eu.pretix.pretixprint.BuildConfig import eu.pretix.pretixprint.R import org.jetbrains.anko.defaultSharedPreferences import org.jetbrains.anko.intentFor import org.jetbrains.anko.selector -import java.lang.RuntimeException import java.text.SimpleDateFormat import java.util.* import kotlin.math.min -class SettingsFragment : PreferenceFragment() { +class SettingsFragment : ChecksPinFragment, PreferenceFragment() { val types = listOf("ticket", "badge", "receipt") + var pendingPinAction: ((pin: String) -> Unit)? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -180,46 +176,21 @@ class SettingsFragment : PreferenceFragment() { valid("") return } - val pinLength = defaultSharedPreferences.getString("pref_pin", "")!!.length - val view = activity.layoutInflater.inflate(R.layout.dialog_pin, null) - val dialog = MaterialAlertDialogBuilder(activity) - .setView(view) - .create() - dialog.setOnShowListener { - val mPinLockListener: PinLockListener = object : PinLockListener { - override fun onComplete(pin: String) { - this.onPinChange(pin.length, pin) - } - - override fun onEmpty() { - } - - override fun onPinChange(pinLength: Int, intermediatePin: String) { - if (defaultSharedPreferences.getString("pref_pin", "") == intermediatePin) { - dialog.dismiss() - valid(intermediatePin) - } - } - } + pendingPinAction = valid + PinDialog().show(childFragmentManager, PinDialog.TAG) + } - val lockView = view.findViewById(R.id.pin_lock_view) as PinLockView - lockView.pinLength = pinLength - lockView.setPinLockListener(mPinLockListener) - val idots = view.findViewById(R.id.indicator_dots) as IndicatorDots - idots.pinLength = pinLength - lockView.attachIndicatorDots(idots); + override fun checkPin(pin: String) { + if (defaultSharedPreferences.getString("pref_pin", "") == pin) { + (childFragmentManager.findFragmentByTag(PinDialog.TAG) as? PinDialog)?.dismiss() + pendingPinAction?.let { it(pin) } } - dialog.show() } - fun startWithPIN(intent: Intent, resultCode: Int? = null, bundle: Bundle? = null) { + fun startWithPIN(intent: Intent) { pinProtect { pin -> intent.putExtra("pin", pin) - if (resultCode != null) { - startActivityForResult(intent, resultCode, bundle) - } else { - startActivity(intent) - } + startActivity(intent) } } } diff --git a/pretixprint/app/src/main/res/drawable/ic_backspace_black_24dp.xml b/pretixprint/app/src/main/res/drawable/ic_backspace_black_24dp.xml new file mode 100644 index 00000000..35b3af30 --- /dev/null +++ b/pretixprint/app/src/main/res/drawable/ic_backspace_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/pretixprint/app/src/main/res/layout/dialog_pin.xml b/pretixprint/app/src/main/res/layout/dialog_pin.xml index 7f1afb19..ba6a2bbf 100644 --- a/pretixprint/app/src/main/res/layout/dialog_pin.xml +++ b/pretixprint/app/src/main/res/layout/dialog_pin.xml @@ -1,30 +1,197 @@ - - - - - + + + + + + + - - + android:minWidth="@dimen/dialog_minwidth"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pretixprint/app/src/main/res/layout/view_keyboard_button.xml b/pretixprint/app/src/main/res/layout/view_keyboard_button.xml new file mode 100644 index 00000000..6191a8ab --- /dev/null +++ b/pretixprint/app/src/main/res/layout/view_keyboard_button.xml @@ -0,0 +1,29 @@ + + + + + + + + \ No newline at end of file diff --git a/pretixprint/app/src/main/res/values-de/strings.xml b/pretixprint/app/src/main/res/values-de/strings.xml index 9b537de1..a79c9807 100644 --- a/pretixprint/app/src/main/res/values-de/strings.xml +++ b/pretixprint/app/src/main/res/values-de/strings.xml @@ -134,4 +134,5 @@ Druck bereit. Antippen um Druckdialog zu öffnen. Einstellungen-PIN setzen Einstellungen mit einer selbstgewählten PIN sperren, die zum Ändern der Drucker-Konfiguration eingegeben werden muss + PIN eingeben \ No newline at end of file diff --git a/pretixprint/app/src/main/res/values-w820dp/dimens.xml b/pretixprint/app/src/main/res/values-w820dp/dimens.xml index 63fc8164..39bd0ff7 100644 --- a/pretixprint/app/src/main/res/values-w820dp/dimens.xml +++ b/pretixprint/app/src/main/res/values-w820dp/dimens.xml @@ -3,4 +3,5 @@ (such as screen margins) for screens with more than 820dp of available width. This would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). --> 64dp + 420dp diff --git a/pretixprint/app/src/main/res/values/attrs.xml b/pretixprint/app/src/main/res/values/attrs.xml new file mode 100644 index 00000000..2dcbe121 --- /dev/null +++ b/pretixprint/app/src/main/res/values/attrs.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/pretixprint/app/src/main/res/values/dimens.xml b/pretixprint/app/src/main/res/values/dimens.xml index c48c9dc5..879b0c15 100644 --- a/pretixprint/app/src/main/res/values/dimens.xml +++ b/pretixprint/app/src/main/res/values/dimens.xml @@ -5,4 +5,5 @@ 30sp 15dp 30dp + 300dp diff --git a/pretixprint/app/src/main/res/values/strings.xml b/pretixprint/app/src/main/res/values/strings.xml index 83bd194e..cd8378c2 100644 --- a/pretixprint/app/src/main/res/values/strings.xml +++ b/pretixprint/app/src/main/res/values/strings.xml @@ -133,4 +133,5 @@ continuous Set settings PIN Lock settings with a custom PIN that must be entered if you want to change printer configuration + Enter PIN