cake_wallet/lib/src/screens/settings/enter_pin_code.dart

236 lines
7.7 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:cake_wallet/palette.dart';
import 'package:flutter/foundation.dart';
import 'package:provider/provider.dart';
import 'package:cake_wallet/theme_changer.dart';
import 'package:cake_wallet/themes.dart';
import 'package:cake_wallet/generated/i18n.dart';
class EnterPinCode extends StatefulWidget {
const EnterPinCode(this.currentPinLength, this.currentPin);
final int currentPinLength;
final List<int> currentPin;
@override
EnterPinCodeState createState() =>
EnterPinCodeState(currentPinLength, currentPin);
}
class EnterPinCodeState extends State<EnterPinCode> {
EnterPinCodeState(this.pinLength, this.currentPin);
final _gridViewKey = GlobalKey();
final _closeButtonImage = Image.asset('assets/images/close_button.png');
final _closeButtonImageDarkTheme =
Image.asset('assets/images/close_button_dark_theme.png');
static final deleteIconImage = Image.asset('assets/images/delete_icon.png');
final int pinLength;
final List<int> currentPin;
List<int> pin;
double _aspectRatio = 0;
void _calcualteCurrentAspectRatio() {
final renderBox =
_gridViewKey.currentContext.findRenderObject() as RenderBox;
final cellWidth = renderBox.size.width / 3;
final cellHeight = renderBox.size.height / 4;
if (cellWidth > 0 && cellHeight > 0) {
_aspectRatio = cellWidth / cellHeight;
}
setState(() {});
}
@override
void initState() {
super.initState();
pin = List<int>.filled(pinLength, null);
WidgetsBinding.instance.addPostFrameCallback(_afterLayout);
}
void _afterLayout(dynamic _) => _calcualteCurrentAspectRatio();
@override
Widget build(BuildContext context) {
final _themeChanger = Provider.of<ThemeChanger>(context);
final _isDarkTheme = _themeChanger.getTheme() == Themes.darkTheme;
return Scaffold(
backgroundColor: Theme.of(context).backgroundColor,
appBar: CupertinoNavigationBar(
leading: ButtonTheme(
minWidth: double.minPositive,
child: FlatButton(
onPressed: () {
Navigator.pop(context, false);
},
child: _isDarkTheme
? _closeButtonImageDarkTheme
: _closeButtonImage),
),
backgroundColor: Theme.of(context).backgroundColor,
border: null),
body: SafeArea(
child: Container(
padding: EdgeInsets.only(left: 40.0, right: 40.0, bottom: 40.0),
child: Column(
children: <Widget>[
Spacer(flex: 2),
Text(S.of(context).enter_your_pin,
style: TextStyle(fontSize: 24, color: Palette.wildDarkBlue)),
Spacer(flex: 3),
Container(
width: 180,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: List.generate(pinLength, (index) {
const size = 10.0;
final isFilled = pin[index] != null;
return Container(
width: size,
height: size,
decoration: BoxDecoration(
shape: BoxShape.circle,
color:
isFilled ? Palette.deepPurple : Colors.transparent,
border: Border.all(color: Palette.wildDarkBlue),
));
}),
),
),
Spacer(flex: 3),
Flexible(
flex: 24,
child: Container(
key: _gridViewKey,
child: _aspectRatio > 0
? GridView.count(
crossAxisCount: 3,
childAspectRatio: _aspectRatio,
physics: const NeverScrollableScrollPhysics(),
children: List.generate(12, (index) {
if (index == 9) {
return Container(
margin: EdgeInsets.all(5.0),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: _isDarkTheme
? PaletteDark.darkThemePinButton
: Palette.darkGrey,
),
);
} else if (index == 10) {
index = 0;
} else if (index == 11) {
return Container(
margin: EdgeInsets.all(5.0),
child: FlatButton(
onPressed: () {
_pop();
},
color: _isDarkTheme
? PaletteDark.darkThemePinButton
: Palette.darkGrey,
shape: CircleBorder(),
child: deleteIconImage,
),
);
} else {
index++;
}
return Container(
margin: EdgeInsets.all(5.0),
child: FlatButton(
onPressed: () {
_push(index);
},
color: _isDarkTheme
? PaletteDark.darkThemePinDigitButton
: Palette.creamyGrey,
shape: CircleBorder(),
child: Text('$index',
style: TextStyle(
fontSize: 23.0,
color: Palette.blueGrey)),
),
);
}),
)
: null))
],
),
)),
);
}
void _showIncorrectPinDialog(BuildContext context) async {
await showDialog<void>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
content: Text(S.of(context).pin_is_incorrect),
actions: <Widget>[
FlatButton(
child: Text(S.of(context).ok),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
});
}
void _push(int num) {
if (_pinLength() >= pinLength) {
return;
}
for (var i = 0; i < pin.length; i++) {
if (pin[i] == null) {
setState(() => pin[i] = num);
break;
}
}
final currentPinLength = _pinLength();
if (currentPinLength == pinLength) {
if (listEquals<int>(pin, currentPin)) {
Navigator.pop(context, true);
} else {
Navigator.pop(context, false);
_showIncorrectPinDialog(context);
}
}
}
void _pop() {
if (_pinLength() == 0) {
return;
}
for (var i = pin.length - 1; i >= 0; i--) {
if (pin[i] != null) {
setState(() => pin[i] = null);
break;
}
}
}
int _pinLength() {
return pin.fold(0, (v, e) {
if (e != null) {
return v + 1;
}
return v;
});
}
}