in_app_purchases_paywall_ui 0.5.0 copy "in_app_purchases_paywall_ui: ^0.5.0" to clipboard
in_app_purchases_paywall_ui: ^0.5.0 copied to clipboard

outdated

A collection of in app purchase Paywall as a UI library. Also handles Purchase success state. Currently only subscriptions are supported.

This package is an in app purchases paywall UI for Flutter

Paywall design for everyone #

This simple to use Paywall UI is developed for the flutter community. Fully customizable and easy to integrate.

Design 1: Simple Paywall #

The Simple Paywall design is a basic design without any animations

Simple Paywall

Design 2: Moritz Paywall #

The second Paywall designed by Moritz is available from version 0.5 and upwards.

Moritz Paywall

Easy integration #

Use the SimplePaywall without a Scaffold or wrap the Paywall in a PaywallScaffold

// Use the Scaffold to also show an App Bar
PaywallScaffold(
  theme: Theme.of(context),
  appBarTitle: "Premium",
  child: // your Paywall as a child
);

SimplePaywall(
  // ...
)

MoritzPaywall(
  // ...
)

Flutter Navigation 2.0 Page #

If you use flutter navigation 2.0 you might want to wrap the scaffold in a page element or use the class PaywallPage:

class PremiumPage extends Page {
  @override
  Route createRoute(BuildContext context) {
    return MaterialPageRoute(
      settings: this,
      builder: (BuildContext context) {
        return PaywallScaffold(
          // ...
        );
      },
    );
  }
}

State control included #

Control the State: PURCHASED to show the Success Page or Purchase in Progress to show a fullscreen loading indicator.

SimplePaywall(
  // add your handler -> extend DefaultPurchaseHandler
  callbackInterface: purchaseHandler,
  purchaseStateStreamInterface: purchaseHandler,
  // ...
)

To control the state, extend DefaultPurchaseHandler and implement your own logic.

class PurchaseHandler extends DefaultPurchaseHandler {
  @override
  Future<bool> purchase(SubscriptionData productDetails) async {
    // show loading
    isPendingPurchase = true;
    // your logic
    await Future.delayed(Duration(seconds: 1));
    // show success purchase and end loading
    purchaseState = PurchaseState.PURCHASED;
    isPendingPurchase = false;
    return true;
  }

  @override
  Future<bool> restore() async {
    // show loading
    isPendingPurchase = true;
    // your logic
    await Future.delayed(Duration(seconds: 1));
    // show success purchase and end loading
    purchaseState = PurchaseState.PURCHASED;
    isPendingPurchase = false;
    return true;
  }
}
Simple Paywall Success state

Easy Integration with linkfive_purchases library #

Since LinkFive is using in_app_purchase package as a dependency, the integration is seamless and effortless.

Pub.dev plugin: linkfive_purchases package


// get subscription data from your provider or from your stream (as described below)
LinkFiveSubscriptionData? linkFiveSubscriptionData = subscriptionData;

// you can use your own strings or use the intl package to automatically generate the subscription strings
final subscriptionListData = linkFiveSubscriptionData?.getSubscriptionData(context: context) ?? [];

SimplePaywall(
    // ...
    callbackInterface: LinkFivePurchases.callbackInterface,
    subscriptionListData: subscriptionListData,
    // ...
});

// That‘s it! Your subscriptions are now automatically included. (paywall state management works as well) 
LinkFive and Flutter works perfectly together

Read more about an easy Flutter Paywall Integration

LinkFive Provider Plugin (easiest version) #

LinkFive created a provider plugin which you can use out of the box: linkfive_purchases_provider

For a fully working paywall including state management. Register the module:

MultiProvider(
  providers: [
    // ...
    ChangeNotifierProvider(
      create: (context) => LinkFiveProvider("API_KEY"),
      lazy: false,
    ),
  ]
)

And pass the callback and pass the subscriptionData from linkfive_purchases_provider

PaywallScaffold(
  child: SimplePaywall(
    callbackInterface: LinkFivePurchases.callbackInterface,
    subscriptionListData: provider.getSubscriptionListData(context),
    // ...
  )
)

Now you have a fully functional subscription system.


Check out the following example: Provider and Navigator Example


implement #

Example usage Simple Paywall: #

class _MyHomePageState extends State<MyHomePage> {
  PurchaseHandler purchaseHandler = PurchaseHandler();
  @override
  Widget build(BuildContext context) {
    return PaywallScaffold(
      // set a theme
      theme: Theme.of(context),
      // appBarTitle for scaffold
      appBarTitle: "Premium",
      child: SimplePaywall(
        // set a theme
          theme: Theme.of(context),
          // set a custom header
          headerContainer: Container(
              margin: EdgeInsets.all(16),
              height: 100,
              decoration: BoxDecoration(
                  borderRadius: BorderRadius.all(Radius.circular(8.0)),
                  image: DecorationImage(
                      fit: BoxFit.cover,
                      alignment: FractionalOffset.center,
                      image: AssetImage('assets/images/premium_bg.png'))),
              child: Container()),
          // Title Bar
          title: "Go Premium",
          // SubTitle
          subTitle: "All features at a glance",
          // Add as many bullet points as you like
          bulletPoints: [
            IconAndText(Icons.stop_screen_share_outlined, "No Ads"),
            IconAndText(Icons.hd, "Premium HD"),
            IconAndText(Icons.sort, "Access to All Premium Articles")
          ],
          // Your subscriptions that you want to offer to the user
          subscriptionListData: [
            SubscriptionData(
                durationTitle: "Yearly",
                durationShort: "1 year",
                price: "€14,99€",
                dealPercentage: 69,
                productDetails: "Dynamic purchase data",
                index: 0),
            SubscriptionData(
                durationTitle: "Quarterly",
                durationShort: "3 Months",
                price: "€6,99",
                dealPercentage: 42,
                productDetails: "Dynamic purchase data",
                index: 2),
            SubscriptionData(
                durationTitle: "Monthly",
                durationShort: "1 month",
                price: "3,99€",
                dealPercentage: 0,
                productDetails: "Dynamic purchase data",
                index: 3)
          ],
          // Shown if isPurchaseSuccess == true
          successTitle: "Success!!",
          // Shown if isPurchaseSuccess == true
          successSubTitle: "Thanks for choosing Premium!",
          // Widget can be anything. Shown if isPurchaseSuccess == true
          successWidget: Container(
              padding: EdgeInsets.only(top: 16, bottom: 16),
              child:
              Row(mainAxisAlignment: MainAxisAlignment.center, children: [
                ElevatedButton(
                  child: Text("Let's go!"),
                  onPressed: () {
                    print("let‘s go to the home widget again");
                  },
                )
              ])),
          // set true if subscriptions are loading
          isSubscriptionLoading: false,
          // if purchase is in progress, set to true. this will show a fullscreen progress indicator
          isPurchaseInProgress: false,
          // to show the success widget
          purchaseState: PurchaseState.NOT_PURCHASED,
          // callback Interface for restore and purchase tap events. Extend DefaultPurchaseHandler
          callbackInterface: purchaseHandler,
          purchaseStateStreamInterface: purchaseHandler,
          // provide your TOS
          tosData:
          TextAndUrl("Terms of Service", "https://www.linkfive.io/tos"),
          // provide your PP
          ppData:
          TextAndUrl("Privacy Policy", "https://www.linkfive.io/privacy"),
          // add a custom campaign widget
          campaignWidget: CampaignBanner(
            theme: Theme.of(context),
            headline: "🥳 Summer Special Sale",
            subContent: Container(
                padding: EdgeInsets.all(8),
                child: CountdownTimer(
                  endTime: DateTime.now()
                      .add(Duration(days: 2, hours: 7))
                      .millisecondsSinceEpoch,
                )),
          )),
    );
  }
}

Change colours and font

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // primary color schema
        primarySwatch: Colors.green,
        // set light or dark
        brightness: Brightness.light,
        // custom icon theme
        iconTheme: IconThemeData(color: Colors.lightGreen),
        // your accentColor
        accentColor: Colors.amber,
        /*
        // and many more color options
        appBarTheme: AppBarTheme(backgroundColor: Colors.white),
        brightness: Brightness.light,
        iconTheme: IconThemeData(color: Colors.red),
        backgroundColor: Colors.purple,
        textTheme: TextTheme(
          button: TextStyle(color: Colors.blueGrey),
          headline5: TextStyle(color: Colors.amber),
          bodyText1: TextStyle(color: Colors.green),
          bodyText2: TextStyle(color: Colors.blue)
        ),
        primaryColor: Colors.cyan,
        primaryColorDark: Colors.green,
        primaryColorLight: Colors.blue
        accentColor: Colors.yellowAccent

        textButtonTheme: TextButtonThemeData(
          style: ElevatedButton.styleFrom(primary: Colors.purple, onPrimary: Colors.red),
        )
        */
      ),
      home: MyHomePage(),
    );
  }
}

Example: Moritz Paywall #

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  PurchaseHandler purchaseHandler = PurchaseHandler();

  @override
  Widget build(BuildContext context) {
    final translations = PaywallL10NHelper.of(context);
    return PaywallScaffold(
      // set a theme
      theme: Theme.of(context),
      // appBarTitle for scaffold
      appBarTitle: "YourApp Premium",
      child: MoritzPaywall(
          // set a theme
          // theme: Theme.of(context),
          // set a custom header
          /*headerContainer: Container(
              margin: EdgeInsets.all(16),
              height: 100,
              decoration: BoxDecoration(
                  borderRadius: BorderRadius.all(Radius.circular(8.0)),
                  image: DecorationImage(
                      fit: BoxFit.cover,
                      alignment: FractionalOffset.center,
                      image: AssetImage('assets/images/premium_bg.png'))),
              child: Container()),*/
          // Title Bar
          title: "Go Premium",
          // SubTitle
          subTitle:
              "Enjoy all the advantages of YourApp with the Premium subscription.",
          continueText: "Continue",
          // Add as many bullet points as you like
          bulletPoints: [
            IconAndText(Icons.stop_screen_share_outlined, "No Ads"),
            IconAndText(Icons.hd, "Premium HD"),
            IconAndText(Icons.sort, "Access to All Premium Articles")
          ],
          // Your subscriptions that you want to offer to the user
          subscriptionListData: [
            SubscriptionData(
                durationTitle: translations.yearly.toTitleCase(),
                durationShort: translations.nmonth(12),
                price: "€14,99€",
                highlightText: "Most popular",
                dealPercentage: 59,
                productDetails: "Dynamic purchase data",
                currencySymbol: "€",
                rawPrice: 14.99,
                monthText: translations.month,
                duration: "P1Y",
                index: 3),
            SubscriptionData(
                durationTitle: translations.quarterly.toTitleCase(),
                durationShort: translations.nmonth(3),
                price: "€8,99",
                dealPercentage: 42,
                productDetails: "Dynamic purchase data",
                currencySymbol: "€",
                rawPrice: 8.99,
                monthText: translations.month,
                duration: "P3M",
                index: 2),
            SubscriptionData(
                durationTitle: translations.monthly.toTitleCase(),
                durationShort: translations.nmonth(1),
                price: "€2,99",
                dealPercentage: 0,
                productDetails: "Dynamic purchase data",
                currencySymbol: "€",
                rawPrice: 2.99,
                monthText: translations.month,
                duration: "P1M",
                index: 1)
          ],
          // Shown if isPurchaseSuccess == true
          successTitle: "Success!!",
          // Shown if isPurchaseSuccess == true
          successSubTitle: "Thanks for choosing Premium!",
          // Widget can be anything. Shown if isPurchaseSuccess == true
          successWidget: Container(
              padding: EdgeInsets.only(top: 16, bottom: 16),
              child:
                  Row(mainAxisAlignment: MainAxisAlignment.center, children: [
                ElevatedButton(
                  child: Text("Let's go!"),
                  onPressed: () {
                    print("let‘s go to the home widget again");
                  },
                )
              ])),
          // set true if subscriptions are loading
          isSubscriptionLoading: false,
          // if purchase is in progress, set to true. this will show a fullscreen progress indicator
          isPurchaseInProgress: false,
          // to show the success widget
          purchaseState: PurchaseState.NOT_PURCHASED,
          // callback Interface for restore and purchase tap events. Extend DefaultPurchaseHandler
          callbackInterface: purchaseHandler,
          purchaseStateStreamInterface: purchaseHandler,
          // provide your TOS
          tosData:
              TextAndUrl("Terms of Service", "https://www.linkfive.io/tos"),
          // provide your PP
          ppData:
              TextAndUrl("Privacy Policy", "https://www.linkfive.io/privacy"),
          // add a custom campaign widget
          /*campaignWidget: CampaignBanner(
            theme: Theme.of(context),
            headline: "🥳 Summer Special Sale",
            subContent: Container(
                padding: EdgeInsets.all(8),
                child: CountdownTimer(
                  endTime: DateTime.now()
                      .add(Duration(days: 2, hours: 7))
                      .millisecondsSinceEpoch,
                )),
          )*/),
    );
  }
}

Change colours and font

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // primary color schema
        primarySwatch: Colors.green,
        // set light or dark
        // brightness: Brightness.dark,
        // custom icon theme
        iconTheme: IconThemeData(color: Colors.lightGreen),
        // your accentColor
        colorScheme: ColorScheme.fromSwatch(accentColor: Colors.amber, brightness: Brightness.dark, primarySwatch: Colors.green, ),
        backgroundColor: Colors.green.shade50,
        cardColor: Colors.grey.shade100,
        elevatedButtonTheme: ElevatedButtonThemeData(
          style: ElevatedButton.styleFrom(primary: Colors.green)
        )
        /*
        // and many more color options
        appBarTheme: AppBarTheme(backgroundColor: Colors.white),
        brightness: Brightness.light,
        iconTheme: IconThemeData(color: Colors.red),
        backgroundColor: Colors.purple,
        textTheme: TextTheme(
          button: TextStyle(color: Colors.blueGrey),
          headline5: TextStyle(color: Colors.amber),
          bodyText1: TextStyle(color: Colors.green),
          bodyText2: TextStyle(color: Colors.blue)
        ),
        primaryColor: Colors.cyan,
        primaryColorDark: Colors.green,
        primaryColorLight: Colors.blue
        accentColor: Colors.yellowAccent

        textButtonTheme: TextButtonThemeData(
          style: ElevatedButton.styleFrom(primary: Colors.purple, onPrimary: Colors.red),
        )
        */
      ),
      supportedLocales: [
        const Locale('en'),
        const Locale('de'),
      ],
      localizationsDelegates: [
        PaywallLocalizations.delegate,
        GlobalMaterialLocalizations.delegate
      ],
      home: MyHomePage(),
    );
  }
}
56
likes
0
pub points
82%
popularity

Publisher

verified publisherlinkfive.io

A collection of in app purchase Paywall as a UI library. Also handles Purchase success state. Currently only subscriptions are supported.

Repository (GitHub)
View/report issues

License

unknown (LICENSE)

Dependencies

flutter, flutter_inappwebview, in_app_purchases_interface

More

Packages that depend on in_app_purchases_paywall_ui