+ private void startNewPatternActivity(String scanned) {
+ Intent intent = new Intent(this, TemplatesActivity.class);
+ Bundle args = new Bundle();
+ args.putString(TemplatesActivity.ARG_ADD_TEMPLATE, scanned);
+ startActivity(intent, args);
+ }
+ private void alertNoTemplateMatch(String scanned) {
+ MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
+ builder.setCancelable(true)
+ .setMessage(R.string.no_template_matches)
+ .setPositiveButton(R.string.add_button,
+ (dialog, which) -> startNewPatternActivity(scanned))
+ .create()
+ .show();
+ }
+ public void onQRScanResult(String text) {
+ Logger.debug("qr", String.format("Got QR scan result [%s]", text));
+
+ if (Misc.emptyIsNull(text) == null)
+ return;
+
+ LiveData<List<TemplateHeader>> allTemplates = DB.get()
+ .getTemplateDAO()
+ .getTemplates();
+ allTemplates.observe(this, templateHeaders -> {
+ ArrayList<MatchedTemplate> matchingFallbackTemplates = new ArrayList<>();
+ ArrayList<MatchedTemplate> matchingTemplates = new ArrayList<>();
+
+ for (TemplateHeader ph : templateHeaders) {
+ String patternSource = ph.getRegularExpression();
+ if (Misc.emptyIsNull(patternSource) == null)
+ continue;
+ try {
+ Pattern pattern = Pattern.compile(patternSource);
+ Matcher matcher = pattern.matcher(text);
+ if (!matcher.matches())
+ continue;
+
+ Logger.debug("pattern",
+ String.format("Pattern '%s' [%s] matches '%s'", ph.getName(),
+ patternSource, text));
+ if (ph.isFallback())
+ matchingFallbackTemplates.add(
+ new MatchedTemplate(ph, matcher.toMatchResult()));
+ else
+ matchingTemplates.add(new MatchedTemplate(ph, matcher.toMatchResult()));
+ }
+ catch (ParcelFormatException e) {
+ // ignored
+ Logger.debug("pattern",
+ String.format("Error compiling regular expression '%s'", patternSource),
+ e);
+ }
+ }
+
+ if (matchingTemplates.isEmpty())
+ matchingTemplates = matchingFallbackTemplates;
+
+ if (matchingTemplates.isEmpty())
+ alertNoTemplateMatch(text);
+ else if (matchingTemplates.size() == 1)
+ model.applyTemplate(matchingTemplates.get(0), text);
+ else
+ chooseTemplate(matchingTemplates, text);
+ });
+ }
+ private void chooseTemplate(ArrayList<MatchedTemplate> matchingTemplates, String matchedText) {
+ final String templateNameColumn = "name";
+ AbstractCursor cursor = new AbstractCursor() {
+ @Override
+ public int getCount() {
+ return matchingTemplates.size();
+ }
+ @Override
+ public String[] getColumnNames() {
+ return new String[]{"_id", templateNameColumn};
+ }
+ @Override
+ public String getString(int column) {
+ if (column == 0)
+ return String.valueOf(getPosition());
+ return matchingTemplates.get(getPosition()).templateHead.getName();
+ }
+ @Override
+ public short getShort(int column) {
+ if (column == 0)
+ return (short) getPosition();
+ return -1;
+ }
+ @Override
+ public int getInt(int column) {
+ return getShort(column);
+ }
+ @Override
+ public long getLong(int column) {
+ return getShort(column);
+ }
+ @Override
+ public float getFloat(int column) {
+ return getShort(column);
+ }
+ @Override
+ public double getDouble(int column) {
+ return getShort(column);
+ }
+ @Override
+ public boolean isNull(int column) {
+ return false;
+ }
+ @Override
+ public int getColumnCount() {
+ return 2;
+ }
+ };
+
+ MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
+ builder.setCancelable(true)
+ .setTitle(R.string.choose_template_to_apply)
+ .setIcon(R.drawable.ic_baseline_auto_graph_24)
+ .setSingleChoiceItems(cursor, -1, templateNameColumn, (dialog, which) -> {
+ model.applyTemplate(matchingTemplates.get(which), matchedText);
+ dialog.dismiss();
+ })
+ .create()
+ .show();
+ }
+ public void onDescriptionSelected(String description) {
+ debug("description selected", description);
+ if (!model.accountListIsEmpty())
+ return;
+
+ BaseDAO.runAsync(() -> {
+ String accFilter = mProfile.getPreferredAccountsFilter();
+
+ TransactionDAO trDao = DB.get()
+ .getTransactionDAO();