ovatu / zettle_flutter

A Flutter wrapper to use the Zettle SDK. With this plugin, your app can easily and accept card payments on Android and iOS using Zettle account / readers.
MIT License
2 stars 9 forks source link

need help with integration in flutter #6

Open mohamedkaddouri opened 1 year ago

mohamedkaddouri commented 1 year ago

received this message but i initiated the zettle sdk as per your documentation. Unhandled Exception: Exception: Zettle SDK is not initialized. You should call Zettle.init(iosClientId, androidClientId, redirectUrl)

davidhole commented 1 year ago

Hi @mohamedkaddouri,

Are you calling Zettle.init before any other methods?

Do you have a code example to share?

mohamedkaddouri commented 1 year ago

Hi @davidhole,

I call the zettle.init after not before any other methods. The app uses the flutter navigator to navigate between pages. One of those pages is zettle login screen. and if you click on the login button. the zettle init function get triggered. But it results in this error:

Error message: Unhandled Exception: Exception: Zettle SDK is not initialized. You should call Zettle.init(iosClientId, androidClientId, redirectUrl)

0 Zettle._throwIfNotInitialized (package:zettle/zettle.dart:24:7)

1 Zettle.requestPayment (package:zettle/zettle.dart:56:5)

2 buildInvoiceTile. (package:payment_app/screens/invoices_overview_screen.dart:276:28)

3 _InkResponseState.handleTap (package:flutter/src/material/ink_well.dart:1154:21)

4 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:275:24)

5 TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:654:11)

6 BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:311:5)

7 BaseTapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:244:7)

8 PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:630:9)

9 PointerRouter._dispat<…>

I do have code to share

class LoginZettleScreen extends StatefulWidget { static String id = 'login_zettle_screen';

@override _LoginZettleScreenState createState() => _LoginZettleScreenState(); }

class _LoginZettleScreenState extends State { String selectedValue = ''; final FocusNode _emailFocusNode = FocusNode(); final FocusNode _passwordFocusNode = FocusNode(); bool _isFocuseOnEmailField = false; bool _isFocuseOnPasswordField = false;

String? _message;

@override void initState() { super.initState(); _emailFocusNode.addListener(() { setState(() { _isFocuseOnEmailField = _emailFocusNode.hasFocus; }); }); _passwordFocusNode.addListener(() { setState(() { _isFocuseOnPasswordField = _passwordFocusNode.hasFocus; }); }); }

@override void dispose() { _emailFocusNode.dispose(); _passwordFocusNode.dispose(); super.dispose(); } bool isChecked = false; Color BillFoxPrimair = Color.fromRGBO(107, 184, 199,1.0); Color Background = Colors.white;

@override Widget build(BuildContext context) { return Scaffold( backgroundColor: Background, body: Padding( padding: const EdgeInsets.symmetric(horizontal: 24.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Hero( tag: 'logo', child: Container( height: 200.0, child: Text('Zettle Login'), ), ), const SizedBox( height: 48.0, ), TextField( focusNode: _emailFocusNode, onChanged: (value) { //Do something with the user input. }, decoration: kTextFieldDecoration .copyWith(hintText: 'Enter your email') .copyWith(prefixIcon: const Icon(Icons.email_outlined)) .copyWith(prefixIconColor: _isFocuseOnEmailField ? BillFoxPrimair : Colors.grey ) ), const SizedBox( height: 30.0, width: 10.0, ), TextField(

            focusNode: _passwordFocusNode,
            onChanged: (value) {
              //Do something with the user input.
            },
            decoration: kTextFieldDecoration

                .copyWith(hintText: 'Enter your password')
                .copyWith(prefixIcon: const Icon(Icons.lock_outlined))
                .copyWith(prefixIconColor: _isFocuseOnPasswordField ? BillFoxPrimair : Colors.grey
            )

        ),
        const SizedBox(
          height: 24.0,
        ),
        RoundedButton(Colors.blue, 'Log in', () async {
            var clientId = "testclientid";
            var zettleInit =
            await Zettle.init(clientId, clientId, "redirectURL");
            setState(() {
              _message = 'init $zettleInit';
            });
          Navigator.pushNamed(context, InvoicesOverViewScreen.id);
        }),
        LabeledCheckbox(
          label: 'Remember me',
          value: isChecked,
          onChanged: (value) {
            isChecked = value;
          },
          leadingCheckbox: isChecked,
        )
      ],
    ),
  ),
);

}

// void onChanged() {} }

davidhole commented 1 year ago

I can see from your error trace that it is thrown when requestPayment is called, but this is not in your example code, so I think that the example is incomplete.

mohamedkaddouri commented 1 year ago

Hi sorry for the late response I was sick last two weeks. I modified my code a little bit. To make it easier to fix the problem. But I cannot get any further I also tried using your example app, this also does not work. Same error it seems.

import 'package:flutter/material.dart'; import 'package:animated_text_kit/animated_text_kit.dart'; import 'package:payment_app/screens/registration_screen.dart'; import 'package:zettle/zettle.dart';

import 'login_screen.dart';

class WelcomeScreen extends StatefulWidget { static String id = 'welcome_screen';

@override _WelcomeScreenState createState() => _WelcomeScreenState(); }

class _WelcomeScreenState extends State with SingleTickerProviderStateMixin { late AnimationController animationController; late Animation animation;

@override void initState() { super.initState();

animationController =
    AnimationController(duration: const Duration(seconds: 1), vsync: this);
animation = ColorTween(begin: Colors.blueGrey, end: Colors.white)
    .animate(animationController);
animationController.forward();
animationController.addListener(() {
  setState(() {});
});

}

@override void dispose() { super.dispose(); animationController.dispose(); }

@override Widget build(BuildContext context) { Color BillFoxPrimair = Color.fromRGBO(107, 184, 199,1.0); return Scaffold( backgroundColor: animation.value, body: Padding( padding: const EdgeInsets.symmetric(horizontal: 24.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Row( children: [ Hero( tag: 'logo', child: SizedBox( height: 60.0, child: Image.asset('images/Billfox_Logo.png'), ), ), AnimatedTextKit( animatedTexts: [ TypewriterAnimatedText( '', textStyle: const TextStyle( fontSize: 45.0, fontWeight: FontWeight.w900), ) ], ), ], ), Hero( tag: 'logo', child: Container( height: 48.0, ), ), RoundedButton(BillFoxPrimair, 'Log in', () async { await Zettle.init( 'clientId', 'clientId', 'https://f527-87-210-179-125.eu.ngrok.io/api/invoices/zettle'); Navigator.pushNamed(context, LoginScreen.id); }) ], ), ), ); } }

class RoundedButton extends StatelessWidget { final Color color; final String buttonTitle; final VoidCallback onPressed;

RoundedButton(this.color, this.buttonTitle, this.onPressed, {super.key});

@override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(vertical: 12.0), child: Material( color: color, borderRadius: BorderRadius.circular(5), elevation: 5.0, child: MaterialButton( onPressed: onPressed,

      height: 42.0,
      child: Text(
        buttonTitle,
        style: const TextStyle(color: Colors.white, fontSize: 20.0),
      ),
    ),
  ),
);

} }