|
@@ -300,6 +300,89 @@ if(res == null)
|
|
|
|
|
|
|
|
Для того чтобы узнать первый запуск или нет, нужно сохранить этот признак в постоянное хранилище. Пример работы с хранилищем есть в [шпаргалке](../shpora/preferences.md). Попробуйте разобраться самостоятельно.
|
|
Для того чтобы узнать первый запуск или нет, нужно сохранить этот признак в постоянное хранилище. Пример работы с хранилищем есть в [шпаргалке](../shpora/preferences.md). Попробуйте разобраться самостоятельно.
|
|
|
|
|
|
|
|
|
|
+### При успешной регистрации нужно автоматически осуществить авторизацию и перейти на Main Screen.
|
|
|
|
|
+
|
|
|
|
|
+При последовательном кодировании у вас получается слишком тяжёлая реализация (много вложенных вызовов)
|
|
|
|
|
+
|
|
|
|
|
+* обработчик клика
|
|
|
|
|
+ * проверки введённых данных
|
|
|
|
|
+ * запрос регистрации
|
|
|
|
|
+ * проверка результата
|
|
|
|
|
+ * запрос авторизации
|
|
|
|
|
+ * проверка результата
|
|
|
|
|
+ * обработка исключений при проверке результата авторизации
|
|
|
|
|
+ * обработка исключений при проверке результата регистрации
|
|
|
|
|
+ * обработка исключений при проверке введённых данных
|
|
|
|
|
+
|
|
|
|
|
+Чтобы избежать многократной вложенности, вспомним, что функцию обратного вызова мы можем объявить отдельно:
|
|
|
|
|
+
|
|
|
|
|
+```kt
|
|
|
|
|
+private fun showAlert(message: String) {
|
|
|
|
|
+ runOnUiThread {
|
|
|
|
|
+ AlertDialog.Builder(this)
|
|
|
|
|
+ .setTitle("Ошибка")
|
|
|
|
|
+ .setMessage(message)
|
|
|
|
|
+ .setPositiveButton("OK", null)
|
|
|
|
|
+ .create()
|
|
|
|
|
+ .show()
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+private val registrationCallback: (response: Response?, error: Exception?)->Unit = {
|
|
|
|
|
+ response, error ->
|
|
|
|
|
+ try {
|
|
|
|
|
+ // тут проверка результата запроса и при необходимости запуск авторизации
|
|
|
|
|
+
|
|
|
|
|
+ } catch (e: Exception) {
|
|
|
|
|
+ // любую ошибку показываем на экране
|
|
|
|
|
+ showAlert(e.message)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+private val authorisationCallback: (response: Response?, error: Exception?)->Unit = {
|
|
|
|
|
+ response, error ->
|
|
|
|
|
+ try {
|
|
|
|
|
+ // тут проверка результата запроса и при необходимости переход на главное окно
|
|
|
|
|
+
|
|
|
|
|
+ } catch (e: Exception) {
|
|
|
|
|
+ // любую ошибку показываем на экране
|
|
|
|
|
+ showAlert(e.message)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// и обработчик кнопки "Регистрация" выглядит уже легче
|
|
|
|
|
+registrationButton.setOnItemClickListener { parent, view, position, id ->
|
|
|
|
|
+ try {
|
|
|
|
|
+ // тут проверки полей
|
|
|
|
|
+
|
|
|
|
|
+ Http.call(
|
|
|
|
|
+ Http.buildRequest(
|
|
|
|
|
+ "http://s4a.kolei.ru/login",
|
|
|
|
|
+ json.toString()
|
|
|
|
|
+ ),
|
|
|
|
|
+ registrationCallback
|
|
|
|
|
+ )
|
|
|
|
|
+ } catch (e: Exception) {
|
|
|
|
|
+ // любую ошибку показываем на экране
|
|
|
|
|
+ showAlert(e.message)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+В итоге общая логика выглядит более структурированной:
|
|
|
|
|
+
|
|
|
|
|
+* обработчик клика
|
|
|
|
|
+ * проверки введённых данных
|
|
|
|
|
+ * запрос регистрации
|
|
|
|
|
+ * обработка исключений при проверке введённых данных
|
|
|
|
|
+* callback регистрации
|
|
|
|
|
+ * проверка результата
|
|
|
|
|
+ * запрос авторизации
|
|
|
|
|
+ * обработка исключений при проверке результата регистрации
|
|
|
|
|
+* callback авторизации
|
|
|
|
|
+ * проверка результата
|
|
|
|
|
+ * обработка исключений при проверке результата авторизации
|
|
|
|
|
+
|
|
|
## Экран авторизации
|
|
## Экран авторизации
|
|
|
|
|
|
|
|

|
|

|
|
@@ -362,8 +445,18 @@ Email проверяется на удовлетворение шаблону и
|
|
|
|
|
|
|
|
Формат ответа - массив информации о фильмах. Нам, судя по вёрстке, нужны пока только название фильма (*name*) и обложка (*poster*). И, скорее всего, идентификатор (*movieId*), чтобы указать его в следующих запросах.
|
|
Формат ответа - массив информации о фильмах. Нам, судя по вёрстке, нужны пока только название фильма (*name*) и обложка (*poster*). И, скорее всего, идентификатор (*movieId*), чтобы указать его в следующих запросах.
|
|
|
|
|
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+Обратите внимание на формат ответа, обязательным почему-то является только одно поле - *movieId*. Возможно это просто ошибка в формировании АПИ, но лучше всё-таки учесть такую вероятность и при отсутствии полей *name* или *poster* просто не добавлять такие элементы в список фильмов.
|
|
|
|
|
+
|
|
|
Для вывода списка фильмов используйте компонент **RecyclerView** (направление пролистывания не указано, так что делайте как вам больше нравится)
|
|
Для вывода списка фильмов используйте компонент **RecyclerView** (направление пролистывания не указано, так что делайте как вам больше нравится)
|
|
|
|
|
|
|
|
|
|
+### Переход между экранами
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+Для перехода между экранами внизу экарана есть панель навигации. Для её реализации есть отдельныё механизм, который мы пока не рассматривали. Вы можете сюда поместить горизонтальный **LinearLayout**.
|
|
|
|
|
+
|
|
|
>6. Реализуйте экран Profile Screen согласно макету:
|
|
>6. Реализуйте экран Profile Screen согласно макету:
|
|
|
> * Данные о пользователе необходимо запрашивать с сервера.
|
|
> * Данные о пользователе необходимо запрашивать с сервера.
|
|
|
> * При нажатии на кнопку "Изменить" необходимо реализовать изменение аватара пользователя:
|
|
> * При нажатии на кнопку "Изменить" необходимо реализовать изменение аватара пользователя:
|