Однажды вечером, залипая в одной соц сети, меня зацепило видео - не своей гениальной режиссурой или постановкой, а именно содержанием. Точнее была показана одна из функциональных возможностей IOS. Суть была в том, что совершенно любой пользователь (даже не крутой хакер или программист) мог интуитивно настроить так называемые shortcuts(в IOS существует отдельное одноименное приложение), которые, в свою очередь, могут выполнять довольно много действий за раз.
Меня не интересовали все обширные возможности shortcuts, моя любовь с первого взгляда в этом приложении - заметки, которые можно вынести на главный экран и по нажатию на ярлык получать уведомление. Сразу же появилась куча идей, как это можно использовать - от вдохновляющий цитат, которые можно получить по одному щелчку, до списка покупок, сразу же отображающиеся в notification bar.
Но как бы я не радовалась этому открытию было одно большое такое НО - я счастливый пользователь Android. И да, я находила приложения, позволяющие создавать shortcut, но ни в одном не было желаемой фичи - по нажатию показывать оповещение, не открывая посторонние приложения. После долгого поиска и отрицания реальности, где у меня нет этого потрясающего приложения в моем замечательном телефончике, на меня снизошло озарение.
Итак, позвольте представиться, студентка метаматематического и программистского направления, в данный момент наслаждающаяся летними каникулами. У меня есть возможности, время и кое-какие знания (спойлер: не совсем точная информация), а также большущее желание. И на таком голом энтузиазме и приступила к проекту.
1. Так как я не располагала никакой яблочной продукцией, то весь желаемый функционал мне пришлось смотреть на том самом видео, упомянутого в начале (стоит ли говорить, что многие вещи мне пришлось додумывать и переделывать под свой вкус?). Как человек, мыслящий визуальными образами, моя первая мысль - быстренько накидать в Figma вид желаемого приложения и его осн функционал (это был только быстрый набросок, так что не все сохранится и кое-что новое добавится)
2. Вот тут мы переходим к шагу номер два - просмотр туториалов на ютубе. На удачу жмакнула на первое попавшееся “андроид приложения за n часов” и начала смотреть. За первые 20 минут я наконец-то узнала что такое пресловутое layout, как объявлять переменные и создавать кнопки. Теперь уже за несколько часов был создан вот такой монстр:
Элементы на левой картинке (ArchiveFrag): SearchView find и ImageButton Plus (плюсик в верхнем правом углу)
Элементы на правой картинке (CreateNote): EditText name_folder, EditText text_body, Button choicebar_split, Button choicebar_get, Button apply (она же create) и ImageButton return
После этого я пошла в ино-ютуб, смотреть более специфичные туториалы и тут в моей голове зазвенели тревожные звоночки (не в плане языка, в нем я бум-бум чуть сильнее, чем в программировании). Выясняется, что “все крутые прогеры” не создают несколько Activity, а используют Fragments. Мое состояние можно было описать лишь как - at this moment he knew he f'cked up. И так как приложения я делала для себя любимой, то естественно надо делать все по красоте. И более продвинутые люди знают, что Activity и Fragments во многом отличаются, начиная от их, собственно, создания, заканчивая способом передачи данных между ними.
В общем, делать было нечего - снесла приложение и начала делать с чистого листа. Благо, все layout можно было скопировать.
3. И вот, после небольшой депрессии из-за произошедшего, я перехожу к третьему акту (но далеко не последнему). В это шаге я просто добавляю весь функционал на уже созданные кнопки.
Здесь же я завожу Adapter для RecycleView, в котором используется GridLayoutManager для отображения элементов.
Adapter самый простой - туториалов куча и код везде +/- одинаковый, но к тому же я создала собственный лист объектов, с которым и работает адаптер - определяется он так:
Здесь показаны кастомные AlertDialod, которые появляются соответственно при нажатии на кнопки Button choicebar_split, Button choicebar_get. Не хочу и не буду мучить тем, как работают эти кнопки, по сравнению со всем остальным там довольно легко (и этим упущением я только что уменьшила эту статью примерно на 2 листа А4)
Небольшое отступление(в который раз): работать с List<ObjMess> было временным решением, поэтому добавила базу данных, состоящую из двух листов. И List<ObjMess> заполняется именно через БД:
4. Я люблю называть этот эпизод - “умей ставить ТЗ правильно”(на самом деле, рабочее название сплошь состояло из нецензурных слов, но ради приличия я их опустила). Внимательный читатель уже мог задаться вопросом: “а после создания заметки, можно ли ее как то открыть и отредактировать?”. На это хочу сказать, во-первых, Ваши мысли намного быстрее моих, поздравляю; во-вторых, на данный момент - нет, нельзя.
Но и я в конце концов дошла до этого озарения и создала третий Fragment, который отображал сохранившиеся данные (он открывается при нажатии на folder в ArchiveFrag, тот, что посередине)
Кстати, это именно тот самый момент, на котором я поняла, что надо использовать базу данных. Чтобы при открытии сохраненной заметки по folder’s id получать нужные данные и отображать их. Ну и еще из примечательного - обновление того же БД, если пользователь изменит/удалит какой-либо текст
Внимательный читатель номер два (или один и тот же читатель, но вдвойне внимательный) может задаться вопросом, а почему, собственно, в этом новом фрагменте отсутствует кнопка для разделения текста (в девичестве choicebar_split). Ответ прост: она мне просто не нужна. При создании заметки в БД уже заносится делитель - двоеточие, точка с запятой или новая строка. И при редактировании в уже сохраненной заметке это деление автоматически применяется. Если же делитель не выбран еще на этапе создании заметки (за что, кстати, дизреспект), то в конечный builder notification будет передана не какая-то фраза из всего написанного пользователем, а все полотно текста (благо, у меня стоит метод отображения для Notification setStyle(new NotificationCompat.BigTextStyle().bigText(intent.getStringExtra("text"))) )
5. Вот и закончились пальцы на одной руке, но хочу обнадежить, пальцы второй руки не пострадают (почти)
сли до этого момента я думала, что делала что-то супер-пупер сложное и невозможное, да и вообще после всего этого преисполнилась в познании, то на этом шаге мой мозг натурально взорвался.
Возвращаемся в родненький ArchiveFrag и видим, что жмакаются не только сами папки, но и кнопки в их правом верхнем углу. И если с delete и choose color (здесь использовала готовую библиотеку AmbilWarnaDialog из 'com.github.yukuku:ambilwarna:2.0.1') все понятно, то с create shortcut не все так радужно, как представлялось (а жаль)
Самое важное и одновременно самое сложное при создании Shortcut это метод setIntent, а точнее описание Intent, который мы передаем. Из EXTRA_TEXT, содержащий id и индекс, будем вытаскивать название папки и фразу из БД соответственно. Важно, что для работы EXTRA_TEXT при создании Intent надо определить метод ACTION_SEND, который позволяет передавать данные между двумя Activity. А откуда же взялось второе Activity, если я работаю исключительно во Fragments (не забываем эпизод великой депрессии из пункта 2)? Через Intent нельзя открыть Service, а мне это было необходимо почти также сильно как кислород. Так что пришлось создать новое activity - ReceivActivity, из которого сервис и открывался.
Builder shortcut:
В ReceiverActivity получаем данные из Shortcut’s Intent, с помощью них выделяем необходимые строки из БД и затем передаем в NotyService уже все готовенькое:
Самое любимое для меня в этом методе - не создается и не показывается layout, а также автоматическое открытие и закрытие Service, которое не требует дополнительных действие. Для меня это была самая важная фишка всего приложения - нажать на иконку и получить оповещение без дополнительных окон и действий.
Service тоже описывается вполне стандартно, только в методе onStartCommand вызываю функцию sendNoty, куда передаю intent, полученный еще в ReceiverActivity, и функцию по созданию канала для оповещения. Intent нужен чтобы в Builder Notification во всяких параметров типа setContentTitle, setContentText можно было бы вытащить по ключам (которые мы тоже передавали) необходимые данные из БД: intent.getStringExtra("title")
5.5 Отдельная головная боль - SearchView, хотя может оно мне больше всего не понравилось, потому что разбиралась с ним на последнем издыхании. Не буду тянуть кота за яи…хвост, и просто скажу, что в Adapter написала метод создающий отфильтрованный список (сам метод вызываю как adapter.getFilter().filter(parserString) в одном из методов setOnQueryTextListener в ArchiveFrag)
Во всех туториалах, которые я находила, почему-то не использовали готовый элемент дизайна SearchView, а использовали menu. Меня этот подход не устраивал, поэтому пришлось повозиться, но в итоге я победила.
Несколько видео с примерами того, как работает приложение:
Небольшая фан статистика: на проект от идеи до релиза было потрачено около 2-х недель (по 4-6 часа в день примерно) (p.s. хотя я растянула это ровно на месяц), строк написано чуть больше 1300 (без учета файлов в папках drawable и layout)
Напоследок, хочу показать небольшую иллюстрацию взаимосвязей между файлами
Легенда:
зеленая стрелка - означает, что процесс происходит в Parent файле
голубая стрелка - по нажатию на определенную кнопку/или автоматически открывается новый JavaClass с layout (например, это Fragments и AlertDialogs)
оранжевый цвет - все, связанное с базой данных
Итоги: по ощущениям в этом, казалось бы, небольшой проекте я изучила разнообразный функционал Java доступный для Android. Все началось с простейших идей - объявление переменных, запоминание информации, вводимой пользователем, и различные события, происходящее по нажатию на кнопки, а потом появились Adapter, Service, SearchView (да, он мне сильно нервы помотал, по этому стоит в одном ряду с вещами, для которых создаются отдельные Java-файлы), разобрала работу двух разных Builder - для Notification и для Shortcut, а также работала с собственным классом и базой данных. Кажется, буду я сама себе устроила курс по Java, от простых задач к сложным, покрывающий довольно обширный пласт знаний (особенно как для абсолютного новичка). Конечно, код не идеальный, не совсем чистый и есть что оптимизировать и куда расти, но самое главное - я получила свое желанное приложение.
RussianWarShip
Прекрасная и вдохновляющая история, которой не хватает самой малости – ссылки на GitHub.
leshchenko84
По коду в примерах грязно, но для студента сойдет
toppal Автор
спасибо за комментарий) я в принципе и не сомневалась, что код довольно грязный и неоптимизированный. думаю, через некоторое время смогу делать лучше)
toppal Автор
спасибо за отзыв!! появилась мотивация изучать java дальше)
если кому-то любопытно и есть какие-нибудь замечания, то вот проект - https://github.com/topperal/note-noty-app