跟Dex学PlatON应用开发–Flutter篇(五)

本章我们完成查看交易列表以及转账的功能。

增加WalletManager方法

这里笔者讲解几个比较重要的函数
1,加载所有钱包列表 – loadAllWallet
代码如下:

  static Future<void> loadAllWallet() async {
   //  获取App的数据路径
    Directory appDocDir = await getApplicationDocumentsDirectory();
    String appDocPath = appDocDir.path;

    Directory directory = Directory("$appDocPath/keyfiles");

    if (!await directory.exists()) {
      return;
    }
   // 遍历目录下所有钱包文件,钱包文件名即为钱包名
    await directory.list(recursive: false).forEach((ele) async {
      String walletName = ele.path.split("/").last.split(".")[0];
      _walletSet.add(walletName);

      String address = await getWalletAddress(walletName);

      _addressWalletNameMap[address] = _walletName;
    });
  }

因为我们创建/导入钱包的钱包文件都是以{钱包名}.json的命名文件存放在keyfiles目录下的,因此我们需要获取walletFiles目录下文件列表,然后提取出钱包名

2, 获取当前选中的钱包名 – getCurrentWalletName

  static Future<String> getCurrentWalletName() async {
    if (_walletName.isNotEmpty) {
      return _walletName;
    }

    final prefs = await SharedPreferences.getInstance();

    String? walletName = prefs.getString("curWallet");

    if (walletName != null) {
      _walletName = walletName;
    } else {
      if (_walletSet.isNotEmpty) {
        _walletName = _walletSet.first;
        prefs.setString("curWallet", _walletName);
      }
    }
    return _walletName;
  }

如果没有选中的钱包, 则获取钱包列表得到第一个钱包作为显示的钱包。然后把选中的钱包名持久化。笔者这里用到了shared_preferences包。

3,切换钱包 – switchWallet

  static switchWallet(String walletName) async {
    final prefs = await SharedPreferences.getInstance();
    prefs.setString("curWallet", walletName);
    _walletName = walletName;
  }

更换当前显示的钱包,都要持久化。

完成改造后,我们就要在App入口的地方调用WalletManager.loadAllWallet函数加载所有的钱包。
调用代码在main.dart文件中, 代码如下:


void main() {
  // 使用测试网
  WidgetsBinding widgetsBinding = WidgetsFlutterBinding.ensureInitialized();

  NetworkParameters.init(BigInt.from(210309), "lat");
  FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
  /// 加载钱包
  _loadWallet();
}
/// 加载钱包
void _loadWallet() async {
  await WalletManager.loadAllWallet();
  runApp(const HomeStatefulWidget());
  /// 设置状态栏为沉浸式
  SystemUiOverlayStyle systemUiOverlayStyle =
      const SystemUiOverlayStyle(statusBarColor: Colors.transparent);
  SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle);
  /// 移除splash
  FlutterNativeSplash.remove();
}

笔者使用了flutter_native_splash 包来实现原生的开屏页功能
钱包加载完成后, 我们需要判断当前是否已有钱包,如果没有则进入导入钱包操作页,否则进入主页面。判断代码main.dar的HomeStatefulWidget类中t代码如下:

... 省略代码
class HomeStatefulWidget extends StatelessWidget {
  const HomeStatefulWidget({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    late String initRouter;
    /// 判断是否有钱包
    if (!WalletManager.isExistWallet()) {
      initRouter = "/import";
    } else {
      initRouter = "/main";
    }
    return GetMaterialApp(
      localizationsDelegates: const [
        RefreshLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalMaterialLocalizations.delegate
      ],
      supportedLocales: const [
        Locale('en'),
        Locale('zh'),
      ],
      initialRoute: initRouter,
      getPages: [
        GetPage(
            name: "/import",
            page: () {
              return AnnotatedRegion<SystemUiOverlayStyle>(
                  child: const OperateMenuStatelessWidget(),
                  value: StatusBarUtil.getDarkOverlayStyle());
            }),
        GetPage(
            name: "/main",
            page: () {
              return AnnotatedRegion<SystemUiOverlayStyle>(
                  child: const MainStatefulWidget(),
                  value: StatusBarUtil.getLightOverlayStyle());
            }),
...省略代码

笔者只用GetX库做路由跳转。

构建主页面

代码在app/page包的main_stateful_widget.dart文件中,控件的使用以及布局代码笔者就不讲解了,大家看源码即可。效果如下图:

用来具体页面的显示容器,具体的内容我们要构建响应的页面

构建资产显示页面

代码在app/page包的asset_stateful_widget.dart文件中。效果如下图:

构建交易记录页面

代码在app/page包的asset_chain_stateful_widget.dart文件中。效果如下图:

在Android篇中我们获取交易记录是通过ATOM的Api接口获取的,在Flutter篇我们通PlatScan获取。获取测试链交易记录的地址为:

https://devnetscan.platon.network/browserserver/transaction/transactionListByAddress

接口的参数:

  String address; // 获取的钱包地址
  int pageNo; // 获取页码
  int pageSize; // 每一页显示的数量
  String txType; // 交易类型,不填则全部获取

返回的参数:

  String errMsg = ""; // 错误信息

  int code = 0; // 错误码 为0 无错误

  BigInt totalCount = BigInt.zero; // 总记录数量

  BigInt displayTotalCount = BigInt.zero; // 显示的数量

  BigInt totalPages = BigInt.zero; // 总页数

  late List<TransactionListResp> data = []; // 记录列表

TransactionListResp 结构体的参数:

  String txHash = ""; //交易hash
  String from = ""; //发送方地址(操作地址)
  String to = ""; //接收方地址
  BigInt seq = BigInt.zero; //排序号
  double value = 0; //金额(单位:von)
  double actualTxCost = 0; //交易费用(单位:von)
  int txType = 0; //
  BigInt serverTime = BigInt.one; //服务器时间
  BigInt timestamp = BigInt.one; //出块时间
  BigInt blockNumber = BigInt.one; //交易所在区块高度
  String failReason = ""; //失败原因
  String receiveType = ""; //此字段表示的是to字段存储的账户类型:account-钱包地址,contract-合约地址
  int txReceiptStatus = 0;

txType交易类型字段代码表的意义如下:

0, 转账
1,EVM合约发布(合约创建)
2, 合约调用(合约执行)
6, ERC20合约发布(合约创建)
7,  ERC20合约调用(合约执行)
8. ERC721合约发布(合约创建)
9, ERC721合约调用(合约执行)
10, ERC1155合约发布(合约创建)
11, ERC1155合约调用(合约执行)
1004, 发起委托(委托)
1005,减持/撤销委托(赎回委托)

其中1155的交易类型,由DQT团队开发,将于下周交付给基金会。

构建发送LAT的页面

代码在app/page包的send_lat_stateful_widget.dart文件中。效果如下图:

笔者这里发送13个LAT给lat104g8hawa0mvsqtxesxyv2xvw04zsghz933wur5账号。可以在交易记录中看到该条记录,如下图:

好啦,本章内容就先到这里啦。

仓库地址: GitHub - DQTechnology/Platon_DevGuideProject

Flutter篇往期链接:

跟Dex学PlatON应用开发–Flutter篇(一)
跟Dex学PlatON应用开发–Flutter篇(二)
跟Dex学PlatON应用开发–Flutter篇(三)
跟Dex学PlatON应用开发–Flutter篇(四)

2 个赞

image

《DQtech 专栏中文版汇总》

https://platonworld.org/zh/special/dqtech-column/

《DQtech Column English Summary》

https://platonworld.org/Topic/dqtech-column/