diff --git a/lib/app.dart b/lib/app.dart index 4988055c..c4a05d08 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -4,6 +4,7 @@ import 'package:device_info/device_info.dart'; import 'package:firebase_analytics/firebase_analytics.dart'; import 'package:firebase_analytics/observer.dart'; import 'package:flutter/material.dart'; +import 'package:gitjournal/screens/purchase_screen.dart'; import 'package:gitjournal/utils/logger.dart'; import 'package:provider/provider.dart'; import 'package:path/path.dart' as p; @@ -135,6 +136,7 @@ class JournalApp extends StatelessWidget { GitHostSetupScreen(stateContainer.completeGitHostSetup), '/onBoarding': (context) => OnBoardingScreen(stateContainer.completeOnBoarding), + '/purchase': (context) => PurchaseScreen(), }, debugShowCheckedModeBanner: false, //debugShowMaterialGrid: true, diff --git a/lib/features.dart b/lib/features.dart index 51d98688..2a4c9d4b 100644 --- a/lib/features.dart +++ b/lib/features.dart @@ -1,3 +1,4 @@ class Features { static bool perFolderConfig = false; + static bool purchaseProModeAvailable = false; } diff --git a/lib/screens/purchase_screen.dart b/lib/screens/purchase_screen.dart new file mode 100644 index 00000000..60ac096e --- /dev/null +++ b/lib/screens/purchase_screen.dart @@ -0,0 +1,153 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:gitjournal/analytics.dart'; + +import 'package:flutter/services.dart'; +import 'package:flutter_inapp_purchase/flutter_inapp_purchase.dart'; + +class PurchaseScreen extends StatefulWidget { + @override + _PurchaseScreenState createState() => _PurchaseScreenState(); +} + +class _PurchaseScreenState extends State { + String _platformVersion = 'Unknown'; + var _skus = ['sku_monthly_min']; + List _iapItems = []; + + StreamSubscription _purchaseUpdatedSubscription; + StreamSubscription _purchaseErrorSubscription; + StreamSubscription _conectionSubscription; + + @override + void initState() { + super.initState(); + initPlatformState(); + } + + Future initPlatformState() async { + // prepare + var result = await FlutterInappPurchase.instance.initConnection; + print('result: $result'); + + // If the widget was removed from the tree while the asynchronous platform + // message was in flight, we want to discard the reply rather than calling + // setState to update our non-existent appearance. + if (!mounted) return; + + try { + _iapItems = await FlutterInappPurchase.instance.getSubscriptions(_skus); + setState(() {}); + print("IAP ITEMS $_iapItems"); + } catch (err) { + print('getSubscriptions error: $err'); + } + + _conectionSubscription = + FlutterInappPurchase.connectionUpdated.listen((connected) { + print('connected: $connected'); + }); + + _purchaseUpdatedSubscription = + FlutterInappPurchase.purchaseUpdated.listen((productItem) { + print('purchase-updated: $productItem'); + }); + + _purchaseErrorSubscription = + FlutterInappPurchase.purchaseError.listen((purchaseError) { + print('purchase-error: $purchaseError'); + }); + } + + @override + Widget build(BuildContext context) { + var theme = Theme.of(context); + var textTheme = theme.textTheme; + + if (_iapItems.isEmpty) { + return const PurchaseLoadingScreen(); + } + var iap = _iapItems[0]; + + // FIXME: This screen needs to be made way way more beautiful + // It's an extrememly important screen + + Widget w = Column( + children: [ + Text('Pro Version', style: textTheme.display2), + Text('Support GitJournal by going Pro', style: textTheme.subhead), + RaisedButton( + child: Text('Subscribe for ${iap.localizedPrice} / month'), + onPressed: () { + FlutterInappPurchase.instance.requestSubscription(_skus[0]); + }, + ), + ], + mainAxisAlignment: MainAxisAlignment.spaceAround, + ); + + w = Container( + child: SafeArea(child: w), + color: theme.scaffoldBackgroundColor, + padding: const EdgeInsets.all(16.0), + ); + + return WillPopScope(child: w, onWillPop: _onWillPop); + } + + Future _onWillPop() async { + getAnalytics().logEvent( + name: "purchase_screen_close", + ); + return true; + } +} + +class PurchaseLoadingScreen extends StatelessWidget { + const PurchaseLoadingScreen({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + var theme = Theme.of(context); + var children = [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + "Loading", + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.display1, + ), + ), + const SizedBox(height: 8.0), + const Padding( + padding: EdgeInsets.all(8.0), + child: CircularProgressIndicator( + value: null, + ), + ), + ]; + + var w = Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: children, + ); + + return WillPopScope( + onWillPop: _onWillPopLoading, + child: Container( + child: SafeArea(child: w), + color: theme.scaffoldBackgroundColor, + padding: const EdgeInsets.all(16.0), + ), + ); + } + + Future _onWillPopLoading() async { + getAnalytics().logEvent( + name: "purchase_screen_close_loading", + ); + return true; + } +} diff --git a/lib/widgets/app_drawer.dart b/lib/widgets/app_drawer.dart index 4fdcba8e..aa7de369 100644 --- a/lib/widgets/app_drawer.dart +++ b/lib/widgets/app_drawer.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_email_sender/flutter_email_sender.dart'; +import 'package:gitjournal/features.dart'; import 'package:launch_review/launch_review.dart'; import 'package:provider/provider.dart'; import 'package:share/share.dart'; @@ -64,6 +65,21 @@ class AppDrawer extends StatelessWidget { ), ), if (setupGitButton != null) ...[setupGitButton, divider], + if (Features.purchaseProModeAvailable) + _buildDrawerTile( + context, + icon: Icons.power, + title: "Go Pro", + onTap: () { + Navigator.pop(context); + Navigator.pushNamed(context, "/purchase"); + + getAnalytics().logEvent( + name: "purchase_screen_open", + ); + }, + ), + if (Features.purchaseProModeAvailable) divider, _buildDrawerTile( context, icon: Icons.note, diff --git a/pubspec.lock b/pubspec.lock index f6e71bc2..c4283317 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -207,6 +207,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.2.1+1" + flutter_inapp_purchase: + dependency: "direct main" + description: + name: flutter_inapp_purchase + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.4" flutter_launcher_icons: dependency: "direct dev" description: diff --git a/pubspec.yaml b/pubspec.yaml index 1a2745db..8abd89b3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -41,6 +41,7 @@ dependencies: font_awesome_flutter: ^8.7.0 sentry: ">=3.0.0 <4.0.0" equatable: ^1.1.0 + flutter_inapp_purchase: ^2.1.4 dev_dependencies: flutter_launcher_icons: "^0.7.2"