/* Copyright 2019 fuwa This file is part of CyberWOW. CyberWOW is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. CyberWOW is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with CyberWOW. If not, see . */ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import '../state.dart'; import '../helper.dart'; import '../logging.dart'; Widget summary(BuildContext context, SyncedState state) { final height = state.height.toString(); final onFire = state.getTransactionPool.length >= 10; final onFireNotice = onFire ? ' 🔥' : ''; final poolLength = state.getTransactionPool.length; final poolLengthNotice = poolLength > 1 ? '[$poolLength] ' : ''; final txNotice = state.getTransactionPool.isEmpty ? '' : poolLengthNotice + state.getTransactionPool.first['id_hash'].substring(0, 6) + ' ...'; return Container( padding: EdgeInsets.only(bottom: 10.0), child: Align( alignment: Alignment.center, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Spacer( flex: 17, ), Image.asset( 'assets/lolnode_icon.png', height: 220, ), Spacer( flex: 7, ), Expanded( flex: 15, child: Row(children: [ Spacer(), AnimatedSwitcher( duration: Duration(milliseconds: 500), child: Text( height, style: Theme.of(context).textTheme.headline4, key: ValueKey(state.height), ), ), AnimatedSwitcher( duration: Duration(milliseconds: 500), child: Text( onFireNotice, style: TextStyle( fontSize: 25, ), key: ValueKey(onFire ? 0 : 1), ), ), Spacer(), ])), AnimatedSwitcher( duration: Duration(milliseconds: 500), child: Text( txNotice, style: Theme.of(context).textTheme.bodyText1, key: ValueKey(poolLength), ), ), Spacer( flex: 1, ), SizedBox( height: 20.0, width: 20.0, child: (state.connected) ? Container() : CircularProgressIndicator( strokeWidth: 2, ), ), ], ), ), ); } Widget rpcView(BuildContext context, String headline6, String body) { return Container( padding: const EdgeInsets.all(10.0), child: Align( alignment: Alignment.topLeft, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( flex: 1, child: SingleChildScrollView( scrollDirection: Axis.vertical, child: Column( children: [ Container( height: 0, margin: const EdgeInsets.only(bottom: 15), ), Text( headline6, style: Theme.of(context).textTheme.headline4, ), Container( height: 1, color: Theme.of(context).primaryColor, margin: const EdgeInsets.only(bottom: 20, top: 20), ), Text( body, style: Theme.of(context).textTheme.bodyText1, ) ], ))) ], ), ), ); } Widget getInfo(BuildContext context, SyncedState state) => rpcView(context, 'info', state.getInfoCache); Widget getTransactionPool(BuildContext context, SyncedState state) { final pool = state.getTransactionPool; const minimalLength = 6; final subTitle = pool.length < minimalLength ? '' : ' ‹${pool.length}›'; return rpcView(context, 'tx pool' + subTitle, state.getTransactionPoolCache); } Widget getConnections(BuildContext context, SyncedState state) { final peers = state.getConnections; const minimalLength = 6; final subTitle = peers.length < minimalLength ? '' : ' ‹${peers.length}›'; return rpcView(context, 'peers' + subTitle, state.getConnectionsCache); } Widget terminalView(BuildContext context, String headline6, SyncedState state) { final input = TextFormField( controller: state.textController, // textInputAction: TextInputAction.next, // autofocus: true, autocorrect: false, enableSuggestions: false, keyboardType: TextInputType.visiblePassword, decoration: InputDecoration( // border: UnderlineInputBorder // OutlineInputBorder // ( // ), // hintText: 'WOW', enabledBorder: UnderlineInputBorder( borderSide: BorderSide( color: Theme.of(context).primaryColor, ), ), border: InputBorder.none, ), onFieldSubmitted: (v) { String autoReplace(final String x) { final words = x.split(' '); if (words.length == 0) { return x; } final head = words.first; final tail = words.sublist(1); final guessHead = head.replaceAll('-', '_'); return [guessHead, ...tail].join(' '); } final _text = state.textController.text.trim(); final line = autoReplace(_text); log.info('textController: $state.controller'); if (line.isNotEmpty) { log.finer('terminal input: $line'); state.appendInput(line); } state.textController.clear(); }, ); return Container( // padding: const EdgeInsets.all(10.0), child: Align( alignment: Alignment.topLeft, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( flex: 1, child: SingleChildScrollView( scrollDirection: Axis.vertical, reverse: true, child: Column( children: [ Text( state.appHook.stdoutCache, style: Theme.of(context).textTheme.bodyText1, ) ], ))), Container( margin: const EdgeInsets.all(10.0), child: input, ), ], ), ), ); } Widget terminal(BuildContext context, SyncedState state) => terminalView(context, 'terminal', state); Widget pageView(BuildContext context, SyncedState state) { void _onPageChanged(int pageIndex) { if (pageIndex != 0) { SystemChannels.textInput.invokeMethod('TextInput.hide'); } state.onPageChanged(pageIndex); } return PageView( controller: state.pageController, onPageChanged: _onPageChanged, children: [ terminal(context, state), summary(context, state), getTransactionPool(context, state), getConnections(context, state), getInfo(context, state), ], ); } Widget build(BuildContext context, SyncedState state) { return Scaffold(body: pageView(context, state)); }