Я написал два поста о процессе активации 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, являются их собственными. |