Add a very basic purchase screen

Along with a 'Go Pro' option in the sidebar. This is extremely ugly and
is therefore disabled by default right now.
This commit is contained in:
Vishesh Handa
2020-04-06 19:26:09 +02:00
parent 9e2d7be716
commit 49f4e334dc
6 changed files with 180 additions and 0 deletions

View File

@ -4,6 +4,7 @@ import 'package:device_info/device_info.dart';
import 'package:firebase_analytics/firebase_analytics.dart'; import 'package:firebase_analytics/firebase_analytics.dart';
import 'package:firebase_analytics/observer.dart'; import 'package:firebase_analytics/observer.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:gitjournal/screens/purchase_screen.dart';
import 'package:gitjournal/utils/logger.dart'; import 'package:gitjournal/utils/logger.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
@ -135,6 +136,7 @@ class JournalApp extends StatelessWidget {
GitHostSetupScreen(stateContainer.completeGitHostSetup), GitHostSetupScreen(stateContainer.completeGitHostSetup),
'/onBoarding': (context) => '/onBoarding': (context) =>
OnBoardingScreen(stateContainer.completeOnBoarding), OnBoardingScreen(stateContainer.completeOnBoarding),
'/purchase': (context) => PurchaseScreen(),
}, },
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,
//debugShowMaterialGrid: true, //debugShowMaterialGrid: true,

View File

@ -1,3 +1,4 @@
class Features { class Features {
static bool perFolderConfig = false; static bool perFolderConfig = false;
static bool purchaseProModeAvailable = false;
} }

View File

@ -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<PurchaseScreen> {
String _platformVersion = 'Unknown';
var _skus = ['sku_monthly_min'];
List<IAPItem> _iapItems = [];
StreamSubscription _purchaseUpdatedSubscription;
StreamSubscription _purchaseErrorSubscription;
StreamSubscription _conectionSubscription;
@override
void initState() {
super.initState();
initPlatformState();
}
Future<void> 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: <Widget>[
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<bool> _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 = <Widget>[
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<bool> _onWillPopLoading() async {
getAnalytics().logEvent(
name: "purchase_screen_close_loading",
);
return true;
}
}

View File

@ -2,6 +2,7 @@ import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_email_sender/flutter_email_sender.dart'; import 'package:flutter_email_sender/flutter_email_sender.dart';
import 'package:gitjournal/features.dart';
import 'package:launch_review/launch_review.dart'; import 'package:launch_review/launch_review.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:share/share.dart'; import 'package:share/share.dart';
@ -64,6 +65,21 @@ class AppDrawer extends StatelessWidget {
), ),
), ),
if (setupGitButton != null) ...[setupGitButton, divider], 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( _buildDrawerTile(
context, context,
icon: Icons.note, icon: Icons.note,

View File

@ -207,6 +207,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.2.1+1" 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: flutter_launcher_icons:
dependency: "direct dev" dependency: "direct dev"
description: description:

View File

@ -41,6 +41,7 @@ dependencies:
font_awesome_flutter: ^8.7.0 font_awesome_flutter: ^8.7.0
sentry: ">=3.0.0 <4.0.0" sentry: ">=3.0.0 <4.0.0"
equatable: ^1.1.0 equatable: ^1.1.0
flutter_inapp_purchase: ^2.1.4
dev_dependencies: dev_dependencies:
flutter_launcher_icons: "^0.7.2" flutter_launcher_icons: "^0.7.2"