Реализовать paywall для android в виде Dialog (покупку реализуем мы)

Цена договорная
10 мая 2022, 20:45 • 5 откликов • 29 просмотров
Нужно реализовать в виде Dialog (а не Activity!) на языке Java (а не котлине!) диалог по продаже подписок в приложении, с переменным количеством инаппов. Логику покупки инаппов реализовывать не нужно, это будет делать наш класс, нужно просто перехватить нажатие кнопки покупки. Использовать потомок класса Dialog, интерфейс пейвола должен быть НЕполноэкранным.

Использовать WebView для чего-либо запрещено, все должно быть сделано на API(то есть используя xml с layout). Просьба использование каких-либо доп.библиотек согласовывать с нами.

Требуемый API:

//объект с таким интерфейсом мы передаем вашему классу
interface PaywallDialogBackend
{
/*у всех методов первые 3 аргумента одинаковые
Activity activity, активити над которой был показан длиалог
PaywallDialog dlg, объект диалога
Object info, различные параметры для внутреннего использования
*/
public void purchase(Activity activity,PaywallDialog dlg,Object info,String productId);

//вызывается когда юзер нажал кнопку Restore purchases
public void restore_purchases(Activity activity,PaywallDialog dlg,Object info);

//вызывается когда юзер пытается просто закрыть диалог
public void onTmeout(Activity activity,PaywallDialog dlg,Object info);
}

//инфа о продуктах
public class PaywallProduct
{
public String productId = "subs_1month"; //внутренний Айди продукта, передается в метод
//purchase бэкэнда
public String prettyPrice = "$3.99"; //красивая цена с наименованием валюты для показа юзеру
public int price_micros = "3990000"; //цена товара умноженная на 1_000_000
public String title = "1 months of access"; //название товара для показа
public int days = 30; //если 0 - это пожизненная лицензия, если > 0 это длительность
// подписки в днях
}

//это надо реализовать
class PaywallDialog
{
public static final int seconds_to_block_use = 30;
//какое время юзер не может просто так закрыть диалог без покупки товара

public static boolean show_savings = true; //показывать ли экономию в процентах относительно
//цены недели

public static String title_text = null; //заголовок диалога.
// Если null то использовать то что стоит в ресурсах
public static String preface_text = null; //текст перед списком продуктов
// Если null то использовать то что стоит в ресурсах

//конструктор. Первые 3 аргумента передаются во все методы интерфейса PaywallDialogBackend
public PaywallDialog(Actvity activity, //поверх чего рисовать
PaywallDialogBackend backend, //этот объект реализует покупку товаров
Object info, //значение которое передавать аргументом info в методах backend


List<PaywallProduct> products, //товары, которые надо показать. Их надо показываьт именно
//в этом порядке
String eula_text,String privacy_policy_text //тексты пользовательского соглашения
//и Политики конфиденциальности - plain text без форматирования.
);

//вызывается из PaywallDialogBackend когда юзер успешно купил товар, при вызове этого метода
//dialog надо закрыть, всю память освободить.
public void close();

public void on_app_suspended(); //вызывается когда юзер переключился в другую прогу
public void on_app_resumed(); //вызывается когда юзер вернулся в нашу прогу
}



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

1.0 Выглядеть примерно должно вот так https://adapty.io/mobile-paywall-library/flexjobs-... (но там не хватает кнопки
restore purchases) или как-то так https://adapty.io/mobile-paywall-library/charging-...


1.1 Диалог (помимо возможности купить подписку) не дает юзеру пользоваться прогой некоторое время (30 секунд - определяется членом класса seconds_to_block_use). В течение этого времени закрыть диалог никакой возможности (кроме как покупкой товара) нет.

1.2 Где-нибудь внизу в диалоге показывается локализуемая надпись "Purchase subscription or wait to return to the app:" 0:28 (где 0:28 - это таймер, уменьшающийся каждую секунду и обновляемый раз в секунду).
После достижения таймером 0 надпись исчезает, и у диалога появляется крестик в правом верхнем углу, (и заместо этой надписи - кнопка Close), нажатие на которые закрывает диалог и приводит к вызову backend.onTmeout()

1.3 когда юзер переключается в другую прогу, вызывается on_app_suspended() когда возвращается
- on_app_resumed() чтобы таймер не засчитывал время, когда наша прога в фоне

1.4 Если при вызове конструктора seconds_to_block_use == 0 то таймер обратного отчета запускать не надо, кнопку и крестик для закрытия диалога показывать сразу же. Это значит что прога уже показала юзеру неотключаемую рекламу и юзер может сразу закрывать это окно.

2.1 Если юзер нажмет кнопку EULA - показать в новом диалоге текст из eula_text (видимо старый со списком товаров придется скрыть, а при закрытии юзером этого диалога с текстом EULA - показать диалог со списком товаров. Новый диалог с текстом EULA - должен иметь соответствующий заголовок ("EULA")

2.2 Если юзер нажмет кнопку Privacy - все то же самое как в п2.1 но используем privacy_policy_text

3.1 Для каждого объекта в List<PaywallProduct> products показываем блок с кнопкой которая приводит к вызову purchase() данного товара. Диалог скрывать не надо при вызове этого метода.

3.2 Блоки для товаров показывать строго в порядке в переданном списке (то есть кнопка пожизненной лицензии может быть и в середине или в самом начале)

4.1 Цена недельной подписки может быть не первым элементом списка.

4.2 Если статическая переменная show_savings == true то для каждого товара показывать в красивом виде экономию в % относительно цены одной недели ("Save 37%"), и цену одной недели ("Only $2.33 per week")(см примеры из п1.0). Для пожизненной лицензии - этого не показывать, конечно.
Соответственно в конструкторе класса найти в списке недельную цену чтобы от нее расчитывать
выгоду. Цену брать из поля price_micros

5.1 Диалог должен иметь заголовок и многострочный текст перед списком товаров (plain text без форматирования). Оба - определяемые в layout, но с возможностью переопределить через статические переменные title_text и preface_text (если они не null)


6.1 Все строки которые видит юзер должны быть локализуемыми

6.2 Диалог должен приятно смотреться на планшетах и смартфонах, в портретной и альбомной ориентации

6.3 Все используемые цвета (фона, текста, кнопок) должны быть именованные, чтобы их можно было подменять через res\values\colors.xml

6.4 Имена ресурсов и переменных стараться писать на английском (пусть ломаном) языке. То есть вместо 'tsvet_economii_v_procentah_fon' писать "savings_economy_percents_bg"

Хочется от вас получить типичное hello world application - при запуске которого получаем activity c одной кнопкой Run. При нажатии на кнопку чтобы открывался этот вот paywall. Чтобы сырцы самого пейвола и этого приложения были в одном каталоге "app" (а не так чтобы activity лежало в app, а реализация пейвола - в lib). То есть хочется тупейший и простейший вариант в плане организации кода и проекта. Так нам будет проще всего перетащить все в наш проект, у нас там хитрая система сборки и все как один проект в gradle идет, не хочется разбираться как там еще один подпроект gradle задействовать прикрутить.