Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial implementation of purchase collection. #308

Merged
merged 12 commits into from
Jul 29, 2024
Merged

Conversation

Joaoaraujo97
Copy link

Realizei a integração do RevenueCat com a aplicação.

  • Foram criados novos Gateway, Repository e Service para a compra do deck pago.

  • Estamos utilizando o RevenueCat como backend da nossa aplicação para verificar se o deck foi comprado ou não, ainda estamos em testes.

  • Caso não haja internet é mostrado somente os decks que são gratuitos ou que já são comprados.

  • Os decks pagos são setados no JSON como isPremium, caso sejam isPremium eles são classificados como !isVisible até que sejam comprados e tornados isVisible e sendo liberados juntamente com os decks restantes.

  • Está pendente ainda a inclusão e configuração da PlayStoreID.

  • Ainda faltam serem inclusos os arquivos StoreKitConfig.storekit e StoreKitTestCertificate.cer.

@lucasbiancogs lucasbiancogs changed the base branch from main to dev July 1, 2024 19:47
Copy link
Contributor

@lucasbiancogs lucasbiancogs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Faltam ainda algumas decisões sobre como os serviços e repositórios devem se comunicar e qual a responsabilidade de cada um, acho interessante falarmos sobre isso numa próxima reunião.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isso é realmente necessário? Se sim, deveria estar nos outros manifestos também.

Verificar principalmente o exported

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Esse é um exemplo, melhor não subir ele junto, manter para testes, ou fazer um deck real pra já inserirmos

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Acho q renomeia esse cara pra mock, pra depois nós tirarmos ele

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isso foi gerado por ti para fazer o revenueCat funcionar ou foi automático pelo XCode?

@@ -14,6 +14,9 @@ String descriptionForException(BaseException exception) {

case ExceptionType.failedToOpenUrl:
return 'Algo deu errado ao tentar abrir o link!';

case ExceptionType.failedPurchase:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
case ExceptionType.failedPurchase:
case ExceptionType.failedToPurchase:

@@ -30,6 +30,10 @@ const collectionsSectionHeaderSeeAll = 'Ver todos';

const collectionsStartNow = 'Começar Agora';

const collectionPurchaseDeck = r'Comprar deck - R$ 0.99';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isso deveria ser variável com o valor.

Suggested change
const collectionPurchaseDeck = r'Comprar deck - R$ 0.99';
String collectionPurchaseDeck(double price) => r'Comprar deck - R$ $(price.toStringAsFixed(2))';

Comment on lines 58 to 69
Future<bool> isVisible({required String id}) async {
final collection = await collectionRepo.getCollection(id: id);

if (collection.isPremium) {
final isAvailable = await collectionPurchaseRepo.isAvailable();
final isPurchased = await collectionPurchaseRepo.getPurchasesInfo();

if (isAvailable.contains(collection.appStoreId) || isAvailable.contains(collection.playStoreId)) {
return !isPurchased.contains(collection.appStoreId) || !isPurchased.contains(collection.playStoreId);
}
}
return collection.isPremium;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

De novo, o isPremium é uma coisa, o isVisible é outra. N deveriam estar associados.

Comment on lines 46 to 55
Future<void> _purchaseInAppCollection(Collection collection) async {
switch (env.platform) {
case SupportedPlatform.ios:
await collectionPurchaseRepo.purchaseInApp(storeId: collection.appStoreId);
break;
case SupportedPlatform.android:
await collectionPurchaseRepo.purchaseInApp(storeId: collection.playStoreId);
break;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIP - Isso está ok, mas ficaria mais claro se tu só retornasse a string e no método tu chamasse o repositório, exemplo:

Suggested change
Future<void> _purchaseInAppCollection(Collection collection) async {
switch (env.platform) {
case SupportedPlatform.ios:
await collectionPurchaseRepo.purchaseInApp(storeId: collection.appStoreId);
break;
case SupportedPlatform.android:
await collectionPurchaseRepo.purchaseInApp(storeId: collection.playStoreId);
break;
}
}
// Dentro do repositório
await collectionPurchaseRepo.purchaseInApp(_collectionStore(collection));
....
String _collectionStore(Collection collection) {
switch (env.platform) {
case SupportedPlatform.ios:
return collection.appStoreId;
case SupportedPlatform.android:
return collection.playStoreId;
}
}

},
);
try {
final isAvailbleList = await collectionPurchaseRepo.isAvailable();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

É melhor expor isso no serviço CollectionPurchaseServices, assim esse serviço nem precisa saber do collectionPurchaseRepo, já q tu quer usar esse serviço aqui. Melhor era na verdade o collection services nem saber nada sobre compra. Pra isso tu teria q angariar essas informações na vm e nela montar o card baseado no serviço de CollecionServices e de CollectionPurchaseServices.

@@ -15,13 +15,15 @@ void main() {
description: 'This collection represents a collection.',
category: 'Category',
tags: const ['Tag 1', 'Tag 2'],
isPremium: false,
appStoreId: 'appStoreId',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

E o playStoreId?

"Tag 2"
],
"isPremium": false,
"appStoreId": "appStoreId",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

E o playStoreId?

@@ -35,6 +37,9 @@ class CollectionCard extends ConsumerWidget {
/// List of tags associated with this collection.
final List<String> tags;

///
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing doc

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ainda falta o doc

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ainda falta o doc

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ainda falta o doc

@@ -41,6 +44,12 @@ class CollectionSerializer implements Serializer<Collection, Map<String, dynamic
final rawContributors = List<Map<String, dynamic>>.from(json[CollectionKeys.contributors] as List);
final contributors = rawContributors.map(contributorSerializer.from).toList();

final isPremium = json[CollectionKeys.isPremium] as bool;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aqui teremos que ou fazer uma migração ou colocar como default false

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Acho q renomeia esse cara pra mock, pra depois nós tirarmos ele

"isPremium": true,
"productInfo": {
"price": 0.99,
"productId": "com.olmps.memo_099_in_app_purchase_deck"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q tal só id?

Comment on lines 10 to 12
"productInfo": {
"price": null,
"productId": null
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Idealmente eu nem colocaria o productInfo se n for premium

/// Updates the collection with the [id] to be premium or not.
Future<void> updatePurchase({required String purchaseId});

Future<List<String>> getPurchaseProducts();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Future<List<String>> getPurchaseProducts();
Future<List<String>> getPurchasedProducts();

Comment on lines 8 to 9
/// Receives purchase information made by the user.
Future<List<String>> getPurchasesInfo();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ser mais específico na documentação e no nome. Q info q é puxada? É o id do produto?

/// Updates the collection with the [id] to be premium or not.
Future<void> updatePurchase({required String purchaseId});

Future<List<String>> getPurchaseProducts();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aqui tbm pode ser mais específico no nome e também falta a documentação


Future<void> _updatePurchaseCollection({required String id}) async {
final collection = await collectionRepo.getCollection(id: id);
final isPurchased = await purchaseRepo.getPurchasesInfo();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Esse uso do verbo no isPurchased faz muita referencia a um booleano, aqui o ideal seria outro nome como, purchasesIds ou remotePurchases.

Comment on lines 142 to 145
await Future.wait<dynamic>([
collectionPurchaseServices.updatePurchasesIfNeeded(),
]);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pq não só colocar no Future.wait acima?

Copy link
Contributor

@lucasbiancogs lucasbiancogs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Colocar no readme abaixo dos sponsors

Revenue

We are currently exploring new approaches to generate revenue with the app. The implementation of the paid deck feature can be found in the code, along with an example of a paid deck. Other decks will not be visible on GitHub to ensure we can properly validate this revenue model.

await _updatePurchaseCollection(id: id);
}

Future<void> _updatePurchaseCollection({required String id}) async {
final collection = await collectionRepo.getCollection(id: id);
final isPurchased = await purchaseRepo.getPurchasesInfo();
final purchasesId = await purchaseRepo.getUserPurchases();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIP

Suggested change
final purchasesId = await purchaseRepo.getUserPurchases();
final purchasesIds = await purchaseRepo.getUserPurchases();

Comment on lines 117 to 107
productInfo: ProductInfo(price: 0.0, id: ''),
// productInfo: ProductInfo(price: 0.0, id: ''),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fazer o teste da serialização do productInfo

Copy link
Contributor

@lucasbiancogs lucasbiancogs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 🚀

@jonata97 jonata97 merged commit d6c8260 into dev Jul 29, 2024
@jonata97 jonata97 deleted the purchase-collections branch July 29, 2024 12:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants