Я написал два поста о процессе активации SMS . В первом я обсуждал использование Twilio API через REST, а во втором я рассмотрел нативные интерфейсы для перехвата SMS, которые мы можем использовать в Android. Теперь пришло время собрать все это воедино и создать единый API-интерфейс. Он должен включать в себя весь процесс пользовательского интерфейса, но быть достаточно гибким, чтобы позволить вам создавать свой собственный опыт.
Строитель
 Я хотел создать пользовательский интерфейс, который был бы довольно типичным и стандартным, скрывая при этом много нюансов.  Моей первой интуицией было просто получить Form и создать пользовательский интерфейс.  Но это не очень хороший подход. 
При извлечении компонента вы открываете весь API базового класса и далее, что создает непонятный API пользовательского интерфейса, поэтому я решил представить API-интерфейс построителя, который выглядит примерно так:
| 
 1 
2 
3 
 | 
TwilioSMS smsAPI = TwilioSMS.create(accountSID, authToken, fromPhone);ActivationForm.create("Signup").        show(s -> Log.p(s), smsAPI); | 
  Здесь происходит несколько вещей.  Я обернул код из SMS-звонков в API-интерфейс TwilioSMS .  Это позволяет мне скрыть детали отправки SMS из класса пользовательского интерфейса ActivationForm .  Вы заметите, что я создаю экземпляр этого класса, используя метод create который принимает заголовок формы.  Затем у меня есть метод show который перезванивает нам с номером телефона, когда активация проходит успешно… 
Поскольку это шаблон строителя, вы можете настроить все виды вещей:
| 
 1 
2 
3 
4 
5 
6 
 | 
ActivationForm.create("Signup").        codeDigits(5). // number of digits in the activation code sent via SMS        enterNumberLabel(string). // text of the label above the number input        includeFab(true). // true if a fab should be shown, by default a fab button will appear in Android only        includeTitleBarNext(true). // true if a next arrow should appear in the title, by default this would appear in non-Android platforms        show(s -> Log.p(s), smsAPI); | 
  Замечательно то, что вы не можете делать все то, чего не должны делать, поскольку класс ActivationForm производным от Object и имеет собственный конструктор. 
Пользовательский интерфейс для формы активации показывает форму поверх текущей формы с пользовательским интерфейсом ввода номера.
Получение списка стран
Я получил список флагов и стран с https://mledoze.github.io/countries/
  Я преобразовал флаги SVG в PNG и добавил их все в файл flags.res .  Это более эффективно, чем открытие нескольких png-файлов из системы.  Я подумал об использовании файлов SVG с нашим транскодером, но решил отказаться от него из-за незрелости и возможных проблем с производительностью инструмента.  Флаги — чувствительные вещи, и ошибка в транскодере может означать, что мы делаем что-то оскорбительное. 
Я не мог пропустить флаги, поскольку они предоставляют визуальный элемент, который полностью меняет восприятие пользовательского интерфейса.
Я подумал о том, чтобы отправить приложение с файлом данных JSON, но оно содержит много ненужной мне информации и весит 500 КБ. Поэтому я написал быстрое приложение, которое просто распечатывало данные в виде массивов, и вставил их в исходный файл. Это важный шаг, так как список может измениться, и нам нужно пройти его снова … Вот как я проанализировал JSON, я просто запустил это в симуляторе и вставил вывод в исходный файл Java:
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 
48 
49 
50 
51 
52 
53 
54 
55 
56 
57 
58 
59 
60 
61 
62 
63 
64 
65 
66 
67 
68 
69 
70 
71 
72 
73 
74 
75 
76 
 | 
private static final CaseInsensitiveOrder cio = new CaseInsensitiveOrder();class Country implements Comparable<Country> {    public final String name;    public final String code;    public final String flag;    public final String isoCode2;    public final String isoCode3;    public Country(String name, String code, String flag, String isoCode2, String isoCode3) {        this.name = name;        this.code = code;        this.flag = flag;        this.isoCode2 = isoCode2;        this.isoCode3 = isoCode3;    }    @Override    public int compareTo(Country o) {        return cio.compare(name, o.name);    }}ArrayList<Country> con = new ArrayList<>();try {    JSONParser p = new JSONParser();    Map<String, Object> dat = p.parseJSON(new InputStreamReader(getResourceAsStream("/countries.json"))); (1)    List<Map<String, Object>> l = (List<Map<String, Object>>)dat.get("root");    for(Map<String, Object> m : l) { (2)        List ll = ((List)m.get("callingCode"));        if(ll != null && ll.size() > 0) {            String name = (String)((Map)m.get("name")).get("common");            String callingCode = (String)ll.get(0);            String code = (String)m.get("cioc");            String flag = null;            if(code != null && code.length() > 0) {                flag = code.toLowerCase();            }            String isoCode2 = (String)m.get("cca2");            String isoCode3 = (String)m.get("cca3");            con.add(new Country(name, callingCode, flag, isoCode2, isoCode3)); (3)        }    }} catch(IOException err) {    Log.e(err);}Collections.sort(con); (4)System.out.println("private static final String[] COUNTRY_NAMES = {");for(Country c : con) { (5)    System.out.println("    \"" + c.name + "\",");}System.out.println("};");System.out.println("private static final String[] COUNTRY_CODES= {");for(Country c : con) {    System.out.println("    \"" + c.code + "\",");}System.out.println("};");System.out.println("private static final String[] COUNTRY_FLAGS = {");for(Country c : con) {    if(c.flag == null) {        System.out.println("    null,");    } else {        System.out.println("    \"" + c.flag + "\",");    }}System.out.println("};");System.out.println("private static final String[] COUNTRY_ISO2 = {");for(Country c : con) {    System.out.println("    \"" + c.isoCode2 + "\",");}System.out.println("};");System.out.println("private static final String[] COUNTRY_ISO3 = {");for(Country c : con) {    System.out.println("    \"" + c.isoCode3 + "\",");}System.out.println("};"); | 
Большая часть этого кода довольно проста:
| 1 | Я загружаю файл JSON из ресурсов | 
| 2 | Я перебираю записи в файле JSON по одной | 
| 3 |   Я Country объект Country на основе данных ввода  | 
| 4 |   Country сортируется благодаря интерфейсу Comparable поэтому я могу просто отсортировать список  | 
| 5 | Теперь я могу просто создать 5 массивов строк, которые я хочу | 
  Да, я знаю, что мог бы сохранить объект Country и работать с ним вместо 5-ти строковых массивов … Я мог бы изменить это в будущем. 
Упаковка в CN1LIB
Бриллиант удивил меня пару недель назад, когда он упаковал мой последний пост как cn1lib . Я думаю, это здорово, если вам нужен перехват SMS-сообщений.
Этот cn1lib сильно отличается по своим целям. Я хотел решить очень конкретный и ограниченный вариант использования проверки пользователя с помощью SMS. Поэтому, хотя у нас есть некоторые общие черты с нашими cn1libs, основная предпосылка довольно далека и это видно.
|   Смотрите оригинальную статью здесь: СОВЕТ: Интерфейс активации и шаблон Builder 
 Мнения, высказанные участниками Java Code Geeks, являются их собственными.  | 

