Сообщество - Android Developers

Android Developers

96 постов 2 039 подписчиков

Популярные теги в сообществе:

8

Гугл хочет 20 тестеров на 14 дней чтобы пустить моё приложение в Play. Ищу

Привет. Я один пилю одно приложение для андроида, PhotoEda — фоткаешь тарелку, оно считает калории и БЖУ. В RuStore лежит, работает. Хочу выложить и в Google Play, и вот тут затык.

Сразу: это моё приложение, разработчик я. Сюда пришёл не рекламировать, а реально просить помощи, ниже объясню.

В 2024 Гугл ввёл прикольное правило для новых разрабов: пока не прогонишь закрытый тест на 20 живых юзерах в течение 14 дней подряд — в открытый Play не пустят. Причём гугл смотрит не «опт-инулся и забил», а на реальную активность, DAU. Без этого Console тупо не даёт нажать кнопку «опубликовать». 20 живых тестеров я нигде не возьму. Соцсетей у проекта нет, бюджета на рекламу нет, делаю один. Поэтому пишу.

Про точность. Прогнал бенч на Nutrition5k — это открытый датасет от гугла, 195 фото блюд с реально взвешенными граммами и калориями (там еду на весах перед съёмкой взвешивали). Лучшая модель из того что я тестил — GPT-5.5, в массе ошибается на ~18%, в калориях на ~28%. Это конечно хуже кухонных весов. Но честно лучше чем «прикинул на глаз», у меня в том числе.

Что норм работает: простые блюда — тарелка пасты, мясо с гарниром, фрукты, тосты, омлет. Внутри есть дневник по дням, график веса, цели по калориям/БЖУ.

Что НЕ работает (для честности): многослойные блюда вроде оливье — путается в составе и считает не пойми что. Большие порции без референса размера (рука,

монета в кадре) занижает — видит «маленькую тарелку», а это была глубокая миска. В тёмном свете путает ингредиенты. Жидкости в стакане — мимо.

Кого ищу:

— андроид, хоть какой современный, лучше версии 9+

— готов 14 дней реально фоткать что ешь, хотя бы 1-2 раза в день. Не «опт-ин и в дальний ящик» — гугл это видит, и неактивный тестер мне не помогает

— готов написать внутри приложения если что-то отвалится, иначе я не починю

Что взамен:

— 2 месяца премиума бесплатно. После релиза тариф будет платным

— прямая связь со мной. Фичи которые тестеры реально просят — внедряю (если в рамках разумного)

Как присоединиться: пиши в личку Gmail (тот, на который у тебя стоит Google Play) и версию андроида. Я добавлю в гугл и скину ссылку для скачивания с гугл.

Это моё первое приложение и первый пост на Пикабу, так что если что не так — не серчайте.

Спасибо если поможете.

#моё #разработка #android #калории #похудение #нейросети

Показать полностью

Вы ж программисты...

А сделайте кто-нибудь приложение для Android, которое будет считать, какой картой выгоднее оплатить покупку для получения максимального кэшбэка?!. Условно 1,5% без округлений или 2% с округлением до 100 рублей покупки. Естественно чтобы можно было настроить условия, а на фронте чтобы ввести только сумму покупки...

3

Прикладная цифровизация для теплоэнергетика

Небольшое продолжение истории из этого поста Ответ на пост «Психанул из-за платных конвертеров и написал свой - бесплатный, приватный и работающий прямо в браузере»
На прошлой неделе я выпустил еще одно приложение. Уже не для метрологов, а для теплотехников/теплоэнергетиков.

Позволяет рассчитать нагрузку по отоплению на здания, посчитать нагрузку гвс макс по сечению трубы, проверить работу УУТЭ и перевести мВт в Гкал и обратно.

Все это уже было у меня в тг боте (еще года 3 назад запускал), но с последними веяниями решил заморочиться и перевести в независимое приложение.

Делал исключительно под собственные потребности, но докрутить практически любой функционал на основе математики можно докрутить в любой момент
https://www.rustore.ru/catalog/app/ru.thermalcalc

3

Pixel wanker

PixelWanker прошёл проверку в Google Play и теперь доступен для скачивания 🎉
Приложение помогает быстрее проверять отступы и выравнивание с помощью аккуратной сетки-оверлея (сверять результат с макетом в фигме например).

Pixel wanker

Что умеет:

  • накладывает сетку поверх любого приложения/экрана;

  • шаг сетки в dp или px;

  • настройка цвета (+ второй цвет полосы для контрастности);

  • сетку можно двигать, зажав палец на ней на секунду.

Google Play: https://play.google.com/store/apps/details?id=com.pavlovalexey.pavlovAlexeySandbox

Показать полностью 1
1

Как sealed class в Kotlin заставили меня признаться: "Дружище, да ты всю жизнь неправильно код писал"

Всем привет, пикабушники! Наверно этот поток сознание уместнее смотрелся бы на хабре, но эта площадка мне нравится решительно больше. Хочу поделиться историей своего просветления. Я адепт старой школы, лет семь назад я писал на Java под Android и свято верил в святость enum'ов и священные ритуалы проверок if (state != null && state == STATE_LOADING && !error). Я не работаю программистом и разработка для меня - хобби. Некоторые крестиком шьют, а я вот буквы в код складываю. Так вот, писал я когда-то на Java и казалось, что я владею миром, пока не сел изучать Kotlin. Ну а что, синтаксис похож, лямбды есть — за неделю освоусь, думал я.

Сегодня я натыкаюсь на одну статью на mobilab про sealed class. Начинаю читать и чувствую, как мое самолюбие джависта начинает медленно и верно трещать по швам. Оказывается, я не просто писал код. Я строил хрупкие карточные домики из boolean-флагов и надеялся, что их не сдует ветром нового требования от продукт-менеджера. Раньше я жил в аду ловли состояний. Мой типичный код управления состоянием экрана аутентификации выглядел как памятник человеческой глупости:

var isLoading: Boolean = false

var errorMessage: String? = null

var isTwoFactorRequired: Boolean = false

var authToken: String? = null

И где-то в глубине onCreateView сидел монстр на 100 строк с вложенными if/else, который пытался угадать, что же сейчас нужно показать пользователю. Добавляем двухфакторку? Легко. Просто добавляем еще один флаг и на 20% увеличиваем энтропию этого блока. Уверен, вы знаете, чем это заканчивается: «Ой, а почему у нас при ошибке показывается индикатор загрузки?».

И теперь, когда я узнал про sealed class, мир перевернулся.

В статье показали, как эта проблема решается элегантно и с невозмутимым спокойствием. Вместо этого зоопарка флагов ты объявляешь одно понятное состояние:

sealed class AuthState {

object Idle : AuthState()

object Loading : AuthState()

data class Success(val token: String) : AuthState()

data class Error(val message: String) : AuthState()

data class TwoFactorRequired(val sessionId: String) : AuthState()

}

И как же это гениально просто. Состояние может быть только одно. Не может быть Success и Error одновременно. Компилятор физически не даст. Это как если бы раньше твоя машина могла быть одновременно и красной, и синей, а теперь ты просто выбираешь один цвет. И все.

Самое волшебное это when.

Когда в коде UI у тебя появляется when (state), компилятор Kotlin превращается в строгого, но заботливого наставника. Он тебя заставляет обработать все возможные варианты. Добавил TwoFactorRequired в sealed class? Поздравляю, проект не соберётся, пока ты не добавишь ветку для его отображения в этом самом when. Это не «ой, надо бы не забыть». Это «забудь и умри (в смысле, не запустишь приложение)». После лет надежд на свою память и на тестировщиков это ощущение будто тебе выдали бронежилет.

Теперь, когда я возвращаюсь к своему старому Java-коду, то смотрю на него с тихой грустью и мысленно прошу у него прощения. Kotlin с его sealed class — это не просто «более приятная Java». Это другой уровень мышления. Это переход от тактики «надеюсь, я ничего не упустил» к стратегии «я не могу это упустить по определению».

P.S. А самый большой кайф это писать unit-тест для такой логики. Подсовываешь Idle и действие Login, получаешь Loading. Подтверждаешь двухфакторку - получаешь Success. Красота, которая даже мне, закоренелому цинику, приносит эстетическое удовольствие.

Показать полностью
15

Волна по "Честной цене" - тру приложение для Android ч.3

Здорово, пикубушники и пикабушницы.

Мы продолжаем нашу замечательную историю про обновление бесплатного приложения, придуманного единомышленниками, тут, на Пикабухе, для удобного подсчета цен в магазинах.

Напомню, давным давно мы заловились с товарищем @Stich.626 чтобы сделать единообразное и бесплатное мобильное приложение + сайт для расчета ценников в магазинах, которое решили не бросать, любить и лелеять, насколько это возможно.

0 - Что делаем сегодня?

В данном посте мы добавляем функционал сравнения ценников, смотрим отзывы пикабушников из магазинов приложений, и конечно же внедряем новые удобства на основе этих самых отзывов (иначе зачем мы их читаем). Готовы? Поехали!

Для Лиги Лени - этот пост опубликован в техническом сообществе, где дальше будет рассказываться много непонятных вещей, в частности, как пишется приложение, что в нем используется и как взаимодействует.

Если вы просто хотите посмотреть программу, скачать / потыкать ее в действии, или просто посмотреть что это за штука, пожалуйста посмотрите обзорный скриншот выше, или проследуйте по ссылкам, которые я публикую без зазрения совести - потому что само приложение бесплатное, и таковым и останется:

https://play.google.com/store/apps/details?id=ru.oneclickstu...

https://www.rustore.ru/catalog/app/ru.oneclickstudio.fairpri...

1 - Разбираемся с понятием сравнения

Итак, в самом начале давайте поразмышляем, зачем вообще нам может быть полезен такой раздел со сравнением, и обусловлена ли необходимость в нем как такового (потому что у нас уже есть прекрасный список, который хоть чуть чуть, но выполняет эти задачи):

  • Когда мы сравниваем один (или несколько) ценников на товарах, обычно мы смотрим их по схожим характеристикам. Например, мы хотим узнать, какое самое дешевое молоко из представленного в магазине. Или пиво. Или хлеб. Или что вы там вечером едите :)

  • В связи с этим у нас формируется некий "паттерн" поведения пользователя в реальной жизни. Ага, я увидел пельмени по 450 рублей за 500 грамм, теперь я хочу сравнить другие пельмени, и посмотреть, что дешевле в пересчете на килограмм.

  • По такой логике наше сравнение обуславливается тем, что у нас есть заведомо известные параметры товара (раз уж взяли пельмени, то это вес в граммах и цена), а также то, что сравнивается один товар из нескольких производителей, или марок.

  • Другими словами, было бы очень удобно "на лету" подсвечивать самое выгодное предложение (каким нибудь зеленым цветом), но при этом ограничить расчеты по одному типу (к сожалению, пельмени не измеряются в литрах, а жаль)

1.1 - Макет, рисуйся!

Как обычно, перед тем, чтобы где то нашкодить сверстать, надо представить "экран" будущей активности, чтобы прикинуть ее на существующих формах, и оценить внешний вид. И конечно нужно понять где будет "точка входа" для этой самой активности, и насколько это удобно для обывателей.

На данный момент нам прекрасно подойдет слой с результатами, который мы видим после каждого расчета. Считаю это удобным, так как при необходимости мы начнем сравнивать сразу с этой цены, а еще нам не нужно выбирать тип сравнения (мы его выбрали ранее), а даже если в этом в расчете нет необходимости, можно просто вернуться назад как обычно.

Для этого немного немного поправим данный слой, добавим новую кнопку, и иконки для наглядности, и выделим функцию шеринга (если ей еще кто то пользуется в этом веке). Действия объясняются буквально одной строкой для вьюх типа Button:

android:drawableLeft="@drawable/back_48px"

1.2 Экран активности

Дальше интереснее. В текущем виде наше сравнение товаров, это как отдельная сущность, которая не должна нас связывать с основной функцией приложения. То есть, в данный момент мы именно сравниваем цены одинакового типа, поэтому экран тоже должен быть отдельный.

Для этого появляется активность CompareActivity со своими слоями, слушателями на физические (или виртуальные) кнопки, а также функцией передачи из одной активности в другую.

Передаем мы, напомню, сведения из последнего расчета

Экран с тестовыми сведениями для наглядности

Экран с тестовыми сведениями для наглядности

Что мы можем тут узреть:

  1. Приветственная карточка, которая повторяет функционал из главной формы, и служит напоминанием, что тут вообще происходит. Кстати, считается плохой практикой учить пользователя что делать (программа должна быть сразу интуитивно понятной), но для самых маленьких я не могу не оставить такую подсказку. И конечно, ее можно скрыть, посредством sharedPreferences, и она не будет надоедать.

  2. Немного переделанный слой из списка, в котором мы сразу назначили цвет для ценника, который будет "перескакивать" на выгодную цену, в зависимости от наших подсчетов. Но так как сейчас результат один, то вначале он и будет самым выгодным, поэтому заранее окрашен.

  3. Еще одна карточка для ввода значений, и добавления их к нашему списку. Постарался уместить ее в одну строку для быстроты ввода, при этом не нарушая читабельности (везде ясно что где вводится)

1.3 Принимаем и передаем сведения

Чтобы информация о последнем расчете попала в нашу активность, ее нужно передать из предыдущей. Для этого мы назначаем отдельный метод для кнопки "Начать сравнение", который остается в главной форме:

Intent intent = new Intent(MainActivity.this, CompareActivity.class);
intent.putExtra("get_compare_price", compare_price);
intent.putExtra("get_compare_weight", compare_weight);
intent.putExtra("get_compare_type", compare_type);
intent.putExtra("get_compare_result", compare_result);
startActivity(intent);

А в следующей активности мы уже запрашиваем эти сведения в onCreate, дополнительно убеждаемся в том что запрошенные поля не пустые (чтобы не получить NullPointerException, если приложение будет выгружено из памяти), и помещаем их на форму через метод добавления первого пункта.

get_compare_price = intent.getStringExtra("get_compare_price");
get_compare_weight = intent.getStringExtra("get_compare_weight");
get_compare_type = intent.getStringExtra("get_compare_type");
get_compare_result = intent.getStringExtra("get_compare_result");

Bundle extra = intent.getExtras();
if (extra !=null) {
SetFirstCompareItem();
}

1.4. Возвращаем значения расчетов к изначальному виду

Когда мы передавали результат из одного экрана на другой, то мы поневоле изменили тип передаваемых сведений. Был double при передаче, а стал String.

Нам нужно вернуть все обратно, чтобы приложение могло сравнивать одинаковые типы данных, а также для сохранения цен (у нас остается две цифры после запятой). Если оставить типы смешанными, расчет может производится некорректно, и подсвечиваться тоже

Поэтому мы меняем типы обратно, посредством

Double.parseDouble(имя_переменной)

1.5. Считаем!

Теперь, когда мы готовы к подсчетам, выполняем стандартные действия из предыдущего экрана, ограничивая размер списка 5 элементами.

Предыдущие действия = означает добавление показателей в массив списка как на первом экране, при этом мы сравниваем новый результат со всеми предыдущими, и если он меньше, мы перекрашиваем самый выгодный элемент в зеленый, а остальным назначаем стандартный.

Способ крайне неудобный, но быстрый в написании, и если бы элементов списка было.. ну штук 50, приложение бы офигело, и сожрало всю память вашего устройства.

При этом, обновился тип для формирования цены - раньше он указывался без привязки с региону, и в некоторых местах цена была с запятой (123,45), а где то с точкой (123.45)

Если для простого списка на главной пофиг, что показывать, то для сравнения такое нельзя оставлять, так как приложение сразу вылетит, информируя нас о несопоставимых типах данных, поэтому приведем их к общему знаменателю вообще везде, оставив в качестве разделителя точку, и указав регион:

String.format(Locale.ENGLISH, "%.2f", price) + " ₽"

1.6 Новые удобства

Чтобы считать было еще удобнее, добавим метод, который после каждого добавления по кнопке (или по клавише с клавиатуры) вновь активирует текстовые поля. Вроде мелочь, а необходимости тыкать по новой в графу цены больше не будет:

private void ClearInputs() {
getInputPriceItemCompare = findViewById(R.id.getInputPriceItemCompare);
getInputWeightGRCompare = findViewById(R.id.getInputWeightGRCompare);

getInputPriceItemCompare.setText("");
getInputWeightGRCompare.setText("");

getInputWeightGRCompare.clearFocus();
getInputPriceItemCompare.requestFocus();
}

2. Новые удобства из отзывов

Так как отзывы я читаю (и даже иногда отвечаю), то будем руководствоваться сразу скриншотами. Итак, рассмотрим вопрос, о котором я раньше не думал:

Действительно, если на большом телефоне начинать тыкать в поля, которые выше клавиатуры, может быть неудобно. С заключениями соглашусь, поэтому пойдем доделаем этот момент.

Чтобы добавить такой способ на нажатие из экранной клавиатуры, воспользуемся объявлением слушателя для наших полей, которые уже есть в форме:

TextInputEditText.OnEditorActionListener

Он добавит в класс новый метод, которому мы будем говорить, что делать после нажатия определенных клавиш на клавиатуре.

К сожалению, устройств (и версий андроида) настолько много, что у одних может показываться галочка (ОК), а у кого то стрелка вперед (NEXT). Чтобы этого избежать, дайте два определим реакцию на обе клавиши:

public boolean onEditorAction (TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_DONE || actionId == EditorInfo.IME_ACTION_NEXT) {
AfterStart();
return true;
}
return false;
}

Тут стоить дать несколько слов о методе AfterStart(), ведь ранее мы использовали другой способ BtnStart(View view)

Как не трудно догадаться, методы сами по себе отличаются, и один унаследован (и объявлен) в слое (View), где мы верстали экран, поэтому вызвать метод, который объявлен в коде мы не можем.

Но и добавлять дополнительные строки, с присвоением кнопки в коде, и создание для нее отдельного слушателя тоже не самая хорошая практика. Ну то есть хорошая конечно, но по времени устаревшая.

Поэтому было решено сделать "костыль" - метод, объявленный через View, вызывает программный метод в коде. Все довольны, добавлено.. ну три строчки кода

3. Что по багам?

3.1 Уже передав версии в релиз, я обнаружил, что часть сведений, которые мы меняли для нового экрана остались в старом формате. Это видно по скриншоту в самом начале:

Этот тип данных поступает в формате String, поэтому часть текста будет обрезаться, если число само по себе ровное (без копеек)

А если же наоборот, передать сумму с копейками, то в новом экране покажется правильный формат, но он по все равно не тот, публикуется как String, а должен быть double

Так как эта часть кода не участвует в методе расчета, то ничего не поломается, но внутренний перфекционист недоволен, и я обязательно поправлю в будущем.

3.2 Для экрана сравнения хорошо бы добавить (в заголовке) что мы вообще сравниваем - килограммы, литры, или штуки. Думаю будет полезно, и главное наглядно

3.3. И возможно, стоит удалять элементы из списка, чтобы переписать что нибудь. Об этом я не подумал, но вы напомните в отзывах

И конечно же предлагайте свои варианты, смотрите, оценивайте, считайте.

Спасибо, что дочитали эту портянку текста, спасибо тем, кто оставляет теплые слова, а также тем, кто закидывает на пачку чипсов.

Всем бобра!

P.S. На обзорном скриншоте я ненароком засветил функцию, которую буду делать потом. Визуально она очень интересна, а сама по себе.. ну такое есть в любой программе, которыми вы могли пользоваться.

Теперь точно пока!

Показать полностью 5
3

Визуальная новелла о Русско-японской войне в стиле... фэнтези

Миноносец Яростный.
Проект начал писать как историческую ролевую текстовую игру, где пользователь выбирая варианты ответов сможет продвигаться по сюжету будучи капитаном одного из кораблей Второго Тихоокеанского флота, выдвигаясь в сторону Порт-Артур для помощи в снятии осады (спойлер: не успели).

А по мере написания игра обрастала новыми идеями, и теперь тут есть ресурсы, которые можно потерять или получить в случайных событиях, есть КНИГИ, да книги, пока две, покупка каждой из которых откроет новую ветку сюжета, отводя игрока от исторических событий к альтернативной истории.

Затем я решил добавить события типа "бой" в которых проходила бы калькуляция ресурсов команды игрока и команды NPC, с возможностью использовать карточки силы, помогающие перевесить чашу весов в сторону игрока.

да, одна из книг Некрономикон

да, одна из книг Некрономикон

В итоге игрок выходит из боя победителем, либо game over и часть накопленных очков игры он сможет использовать при очередной попытке пройти игру (тот самый рогалик). Эта идея еще не реализована, а только на бумаге.

Игра на сегодняшний день совсем не закончена, написана на 15% от начальной задумки. Проект остановился, когда я выходил на финишный этап в своей учебе. Пришлось отоложить, чтобы не провалить учебные проекты. Учебу я недавно закончил и вот зачем пишу сейчас тут на Пикабу - требуется вдохновения писать новые сюжетные арки, местами не хватает опыта правильно собрать проект такого типа.

// скажи что-нибудь на програмистовском: Стек не игровой, вместо unity стандартный набор в андроид студии для приложенек на котлин: MVVM, SingleActivity(+Fragments), Koin, Jetpack Navigation Component и тд. Почему таковы выбор стека? Учеба моя и планы на будущее связаны с продуктовой разработкой приложений, а не игровой, по этому это приложение как практика в основном направлении. На данном этапе мне понятно, что работать на таком стеке оно может и закончить его я смогу. Возможно стоит добавить dagger hilt.

Резюме: Кто хочет попробовать - скачайте и пробуйте, игра бесплатная и без рекламы. Кто шарит за разработку - можем продолжать развивать приложение в команде. Кто шарит за лирику - писать сюжетные арки тоже нужны талантливые люди) Написать мне можно на гитхабе в комментариях к проекту, или тут в комментариях. Спасибо всем, кто послушал.

скачать в плеймарет: https://play.google.com/store/apps/details?id=com.pavlovalexey.torpedo
код проекта в открытом доступе: https://github.com/AlexeyJarlax/Visual_Novel_Torpedo_boat_Fury

Показать полностью 4
49

А заблокируют ли gmail?1

А заблокируют ли gmail?

Без ютуба кое-как справимся, я вот уже практически полностью мигрировал на сервисы Яндекс, а что если заблокируют сервис gmail? Почтой их не пользуюсь, но все андроид устройства живут на этих аккаунтах.
Как быть, есть ли какое-то решение, можно ли уже как-то заранее подготовиться? Ведь вероятность такая есть, и все к этому стремится.

Показать полностью 1
Отличная работа, все прочитано!

Темы

Политика

Теги

Популярные авторы

Сообщества

18+

Теги

Популярные авторы

Сообщества

Игры

Теги

Популярные авторы

Сообщества

Юмор

Теги

Популярные авторы

Сообщества

Отношения

Теги

Популярные авторы

Сообщества

Здоровье

Теги

Популярные авторы

Сообщества

Путешествия

Теги

Популярные авторы

Сообщества

Спорт

Теги

Популярные авторы

Сообщества

Хобби

Теги

Популярные авторы

Сообщества

Сервис

Теги

Популярные авторы

Сообщества

Природа

Теги

Популярные авторы

Сообщества

Бизнес

Теги

Популярные авторы

Сообщества

Транспорт

Теги

Популярные авторы

Сообщества

Общение

Теги

Популярные авторы

Сообщества

Юриспруденция

Теги

Популярные авторы

Сообщества

Наука

Теги

Популярные авторы

Сообщества

IT

Теги

Популярные авторы

Сообщества

Животные

Теги

Популярные авторы

Сообщества

Кино и сериалы

Теги

Популярные авторы

Сообщества

Экономика

Теги

Популярные авторы

Сообщества

Кулинария

Теги

Популярные авторы

Сообщества

История

Теги

Популярные авторы

Сообщества