magic_flutter 1.1.5 copy "magic_flutter: ^1.1.5" to clipboard
magic_flutter: ^1.1.5 copied to clipboard

discontinuedreplaced by: magic_sdk
PlatformAndroidiOS

A Flutter plugin to integrate Magic SDK with native android and ios support

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:magic_flutter/magic_flutter.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: "Magic SDK Sample",
      theme: ThemeData(primarySwatch: Colors.deepPurple),
      home: InitializeApp(),
    );
  }
}

class InitializeApp extends StatelessWidget {
  final publisherKey = "xxxxxxx";

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Magic plugin sample"),
      ),
      body: FutureBuilder(
        future: Magic.initializeMagic(
            publisherKey: publisherKey,
            //providing testnet rpcURL and chain id
            rpcURL: "your rpc url",
            chainID: "xxxxx"),
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.done) {
            if (snapshot.hasData) {
              return LoginPage();
            } else {
              print(snapshot.error);
              return Container(
                alignment: Alignment.center,
                child: Text("Something went wrong. Failed to initialize Magic"),
              );
            }
          } else
            return Center(child: CircularProgressIndicator());
        },
      ),
    );
  }
}

class LoginPage extends StatefulWidget {
  @override
  _LoginPageState createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
  final formKey = GlobalKey<FormState>();
  bool isBusy = false;
  final emailController = TextEditingController();

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: isBusy
          ? Center(
              child: Container(
              child: Text('Please verify your mail',
                  style: TextStyle(
                      color: Colors.black, fontWeight: FontWeight.bold)),
            ))
          : Form(
              key: formKey,
              autovalidateMode: AutovalidateMode.onUserInteraction,
              child: Padding(
                padding:
                    const EdgeInsets.symmetric(vertical: 8.0, horizontal: 20),
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    TextFormField(
                      controller: emailController,
                      decoration: InputDecoration(
                        hintText: "Enter your email id",
                      ),
                      validator: (value) {
                        if (!value!.isValidEmail) return "Enter a valid email";
                        return null;
                      },
                    ),
                    SizedBox(height: 24),
                    ElevatedButton(
                      onPressed: () => login(context),
                      child: Text("LogIn"),
                    ),
                  ],
                ),
              ),
            ),
    );
  }

  Future<void> login(BuildContext context) async {
    if (formKey.currentState!.validate()) {
      try {
        setState(() {
          isBusy = true;
        });
        await Magic.loginWithMagicLink(
            email: emailController.text, showLoadingUI: false);
        setState(() {
          isBusy = false;
        });
        Navigator.of(context).pushReplacement(
          MaterialPageRoute(
            builder: (context) => HomePage(),
          ),
        );
      } catch (e) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: Text((e as PlatformException).message!),
          ),
        );
      }
    }
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  bool isUserLoggedIn = false;
  bool isBusy = false;
  late String userAccount;
  String userBalance = '0 BNB';
  final formKey = GlobalKey<FormState>();
  final addressController = TextEditingController();
  final amountController = TextEditingController();

  @override
  void dispose() {
    addressController.dispose();
    amountController.dispose();
    super.dispose();
  }

  @override
  void initState() {
    isLoggedIn(context);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: true,
      appBar: AppBar(
        title: Text("Home Page"),
        actions: [
          isUserLoggedIn
              ? ElevatedButton.icon(
                  icon: Icon(Icons.logout_outlined),
                  label: Text('Logout',
                      style: TextStyle(fontWeight: FontWeight.w500)),
                  onPressed: () => logout(context),
                )
              : SizedBox()
        ],
      ),
      body: ListView(children: [
        FutureBuilder<GetMetaDataResponse>(
          future: Magic.getMetaData(),
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.done) {
              if (snapshot.hasError) {
                return Container(
                  alignment: Alignment.center,
                  child: Text('Something went wrong while fetching data'),
                );
              }
              userAccount = snapshot.data!.publicAddress;
              return Padding(
                padding: const EdgeInsets.all(8.0),
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.start,
                  children: [
                    ListTile(
                      title: Text('Email address',
                          style: TextStyle(fontWeight: FontWeight.w500)),
                      subtitle: Text(snapshot.data!.email),
                    ),
                    ListTile(
                      title: Text('Public address',
                          style: TextStyle(fontWeight: FontWeight.w500)),
                      subtitle: SelectableText(userAccount),
                      trailing: TextButton.icon(
                          onPressed: () async {
                            await Clipboard.setData(
                                ClipboardData(text: userAccount));
                            showBar(context, 'Address copied');
                          },
                          icon: Icon(
                            Icons.copy_outlined,
                            color: Colors.green,
                          ),
                          label: Text('Copy')),
                    ),
                    ListTile(
                      title: Text('User Balance',
                          style: TextStyle(fontWeight: FontWeight.w500)),
                      subtitle: Text(userBalance),
                      trailing: TextButton.icon(
                          onPressed: () => getUserBalance(context),
                          icon: Icon(
                            Icons.refresh_outlined,
                            color: Colors.green,
                          ),
                          label: Text('Refresh balance')),
                    ),
                    SizedBox(height: 20),
                    Form(
                      key: formKey,
                      autovalidateMode: AutovalidateMode.onUserInteraction,
                      child: Padding(
                        padding: const EdgeInsets.symmetric(
                            vertical: 8.0, horizontal: 20),
                        child: Column(children: [
                          TextFormField(
                            controller: addressController,
                            decoration: InputDecoration(
                              hintText: "Enter receiver address",
                            ),
                            validator: (value) {
                              if (value == '' || value == null)
                                return "Enter a valid address";
                              return null;
                            },
                          ),
                          SizedBox(height: 20),
                          TextFormField(
                            controller: amountController,
                            decoration: InputDecoration(
                              hintText: "Enter amount in BNB",
                            ),
                            validator: (value) {
                              if (value == '' || value == null)
                                return "Enter a valid amount";
                              return null;
                            },
                          ),
                          SizedBox(height: 30),
                          ElevatedButton(
                              style: ElevatedButton.styleFrom(
                                  alignment: Alignment.center,
                                  padding: EdgeInsets.all(12)),
                              onPressed: () => sendTransaction(
                                  context,
                                  addressController.text,
                                  amountController.text),
                              child: Text(
                                'Send transaction',
                                style: TextStyle(fontWeight: FontWeight.bold),
                              )),
                        ]),
                      ),
                    ),
                    Divider(),
                    SignMessageForm(fromAddress: userAccount),
                  ],
                ),
              );
            }
            return Container(
              alignment: Alignment.center,
              child: CircularProgressIndicator(),
            );
          },
        ),
      ]),
    );
  }

  Future<void> isLoggedIn(BuildContext context) async {
    try {
      setState(() {
        isBusy = true;
      });
      bool value = await Magic.isLoggedIn();
      setState(() {
        isBusy = false;
        isUserLoggedIn = value;
      });
    } catch (e) {
      showBar(context, (e as PlatformException).message!);
    }
  }

  Future<void> sendTransaction(
      BuildContext context, String receiverAddress, String sendAmount) async {
    try {
      setState(() {
        isBusy = true;
      });
      String value = await Magic.sendTransaction(
          from: userAccount,
          to: receiverAddress,
          amount: sendAmount,
          gasLimit: "21000",
          gasPrice: "10000000000");
      setState(() {
        isBusy = false;
      });
      showBar(context, 'Transaction successful $value');
    } catch (e) {
      showBar(context, (e as PlatformException).message!);
    }
  }

  Future<void> getUserBalance(BuildContext context) async {
    try {
      setState(() {
        isBusy = true;
      });
      String value = await Magic.getDynamicContractUserBalance(
          contractABI: '',
          byteCode: "",
          accountAddress: userAccount,
          contractAddress: "");
      setState(() {
        isBusy = false;
        userBalance = value + ' GFX';
      });
      showBar(context, 'Balance updated\nYour current balance is $userBalance');
    } catch (e) {
      showBar(context, (e as PlatformException).message!);
    }
  }

  Future<void> logout(BuildContext context) async {
    try {
      bool value = await Magic.logout();
      if (value) {
        Navigator.of(context).pushReplacement(
          MaterialPageRoute(
            builder: (context) => LoginPage(),
          ),
        );
      } else {
        showBar(context, 'Logout failed');
      }
    } catch (e) {
      showBar(context, (e as PlatformException).message!);
    }
  }

  showBar(BuildContext context, String title) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text(title),
      ),
    );
  }
}

extension EmailValidator on String {
  bool get isValidEmail => RegExp(
          r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+")
      .hasMatch(this);
}

class SignMessageForm extends StatefulWidget {
  final String fromAddress;

  const SignMessageForm({Key? key, required this.fromAddress})
      : super(key: key);

  @override
  State<SignMessageForm> createState() => _SignMessageFormState();
}

class _SignMessageFormState extends State<SignMessageForm> {
  final _formKey = GlobalKey<FormState>();

  String? message;

  void onSaveMessage(value) {
    message = value;
  }

  bool isBusy = false;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 20),
      child: Form(
        key: _formKey,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('Sign Message',
                style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16)),
            SizedBox(
              height: 10,
            ),
            Text("Eth Sign"),
            SizedBox(
              height: 10,
            ),
            TextFormField(
              decoration: InputDecoration(labelText: "Message"),
              validator: (value) {
                if (value == '' || value == null)
                  return "This field is required";
                return null;
              },
              onChanged: onSaveMessage,
            ),
            SizedBox(height: 20),
            Center(
              child: ElevatedButton(
                  style: ElevatedButton.styleFrom(
                      alignment: Alignment.center, padding: EdgeInsets.all(12)),
                  onPressed: () async {
                    _formKey.currentState?.save();

                    bool? valid = _formKey.currentState?.validate();

                    if (valid == null || !valid) {
                      return;
                    }

                    try {
                      setState(() {
                        isBusy = true;
                      });
                      String value = await Magic.sign(
                          fromAccount: widget.fromAddress, message: message!);
                      setState(() {
                        isBusy = false;
                      });
                      showBar(context, 'Signed message! hash : $value');
                    } catch (e) {
                      showBar(context, (e as PlatformException).message!);
                    }
                  },
                  child: Text(
                    'Sign message',
                    style: TextStyle(fontWeight: FontWeight.bold),
                  )),
            ),
          ],
        ),
      ),
    );
  }

  showBar(BuildContext context, String title) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text(title),
      ),
    );
  }
}
5
likes
140
pub points
0%
popularity

Publisher

unverified uploader

A Flutter plugin to integrate Magic SDK with native android and ios support

Repository (GitLab)
View/report issues

Documentation

API reference

License

MIT (LICENSE)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on magic_flutter