pretty_qr_code 3.0.0
pretty_qr_code: ^3.0.0 copied to clipboard
Pretty QR code for Flutter. You can round the edges with parameter or use the standard view.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:pretty_qr_code/pretty_qr_code.dart';
void main() {
runApp(const PrettyQrExampleApp());
}
class PrettyQrExampleApp extends StatelessWidget {
const PrettyQrExampleApp({
super.key,
});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.black,
),
),
home: const PrettyQrHomePage(),
);
}
}
class PrettyQrHomePage extends StatefulWidget {
const PrettyQrHomePage({
super.key,
});
@override
State<PrettyQrHomePage> createState() => _PrettyQrHomePageState();
}
class _PrettyQrHomePageState extends State<PrettyQrHomePage> {
@protected
late QrCode qrCode;
@protected
late QrImage qrImage;
@protected
late PrettyQrDecoration decoration;
@override
void initState() {
super.initState();
qrCode = QrCode.fromData(
data: 'https://pub.dev/packages/pretty_qr_code',
errorCorrectLevel: QrErrorCorrectLevel.H,
);
qrImage = QrImage(qrCode);
decoration = const PrettyQrDecoration(
shape: PrettyQrSmoothSymbol(
color: Color(0xFF74565F),
),
image: _PrettyQrSettings.kDefaultPrettyQrDecorationImage,
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text('Pretty QR Code'),
),
body: Align(
alignment: Alignment.topCenter,
child: ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 1024,
),
child: LayoutBuilder(
builder: (context, constraints) {
final safePadding = MediaQuery.of(context).padding;
return Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (constraints.maxWidth >= 720)
Flexible(
flex: 3,
child: Padding(
padding: EdgeInsets.only(
left: safePadding.left + 24,
right: safePadding.right + 24,
bottom: 24,
),
child: _PrettyQrAnimatedView(
qrImage: qrImage,
decoration: decoration,
),
),
),
Flexible(
flex: 2,
child: Column(
children: [
if (constraints.maxWidth < 720)
Padding(
padding: safePadding.copyWith(
top: 0,
bottom: 0,
),
child: _PrettyQrAnimatedView(
qrImage: qrImage,
decoration: decoration,
),
),
Expanded(
child: SingleChildScrollView(
padding: safePadding.copyWith(top: 0),
child: _PrettyQrSettings(
decoration: decoration,
onChanged: (value) => setState(() {
decoration = value;
}),
),
),
),
],
),
),
],
);
},
),
),
),
);
}
}
class _PrettyQrAnimatedView extends StatefulWidget {
@protected
final QrImage qrImage;
@protected
final PrettyQrDecoration decoration;
const _PrettyQrAnimatedView({
required this.qrImage,
required this.decoration,
});
@override
State<_PrettyQrAnimatedView> createState() => _PrettyQrAnimatedViewState();
}
class _PrettyQrAnimatedViewState extends State<_PrettyQrAnimatedView> {
@protected
late PrettyQrDecoration previosDecoration;
@override
void initState() {
super.initState();
previosDecoration = widget.decoration;
}
@override
void didUpdateWidget(
covariant _PrettyQrAnimatedView oldWidget,
) {
super.didUpdateWidget(oldWidget);
if (widget.decoration != oldWidget.decoration) {
previosDecoration = oldWidget.decoration;
}
}
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(16),
child: TweenAnimationBuilder<PrettyQrDecoration>(
tween: PrettyQrDecorationTween(
begin: previosDecoration,
end: widget.decoration,
),
curve: Curves.ease,
duration: const Duration(
milliseconds: 240,
),
builder: (context, decoration, child) {
return PrettyQrView(
qrImage: widget.qrImage,
decoration: decoration,
);
},
),
);
}
}
class _PrettyQrSettings extends StatefulWidget {
@protected
final PrettyQrDecoration decoration;
@protected
final ValueChanged<PrettyQrDecoration>? onChanged;
@visibleForTesting
static const kDefaultPrettyQrDecorationImage = PrettyQrDecorationImage(
image: AssetImage('images/flutter.png'),
position: PrettyQrDecorationImagePosition.embedded,
);
const _PrettyQrSettings({
required this.decoration,
this.onChanged,
});
@override
State<_PrettyQrSettings> createState() => _PrettyQrSettingsState();
}
class _PrettyQrSettingsState extends State<_PrettyQrSettings> {
@protected
Color get shapeColor {
var shape = widget.decoration.shape;
if (shape is PrettyQrSmoothSymbol) return shape.color;
if (shape is PrettyQrRoundedSymbol) return shape.color;
return Colors.black;
}
@protected
bool get isRoundedBorders {
var shape = widget.decoration.shape;
if (shape is PrettyQrSmoothSymbol) {
return shape.roundFactor > 0;
} else if (shape is PrettyQrRoundedSymbol) {
return shape.borderRadius != BorderRadius.zero;
}
return false;
}
@override
Widget build(BuildContext context) {
return Column(
children: [
LayoutBuilder(
builder: (context, constraints) {
return PopupMenuButton(
onSelected: changeShape,
constraints: BoxConstraints(
minWidth: constraints.maxWidth,
),
initialValue: widget.decoration.shape.runtimeType,
itemBuilder: (context) {
return [
const PopupMenuItem(
value: PrettyQrSmoothSymbol,
child: Text('Smooth'),
),
const PopupMenuItem(
value: PrettyQrRoundedSymbol,
child: Text('Rounded rectangle'),
),
];
},
child: ListTile(
leading: const Icon(Icons.format_paint_outlined),
title: const Text('Style'),
trailing: Text(
widget.decoration.shape is PrettyQrSmoothSymbol ? 'Smooth' : 'Rounded rectangle',
style: Theme.of(context).textTheme.titleSmall,
),
),
);
},
),
SwitchListTile.adaptive(
value: shapeColor != Colors.black,
onChanged: (value) => toggleColor(),
secondary: const Icon(Icons.color_lens_outlined),
title: const Text('Colored'),
),
SwitchListTile.adaptive(
value: isRoundedBorders,
onChanged: (value) => toggleRoundedCorners(),
secondary: const Icon(Icons.rounded_corner),
title: const Text('Rounded corners'),
),
const Divider(),
SwitchListTile.adaptive(
value: widget.decoration.image != null,
onChanged: (value) => toggleImage(),
secondary: Icon(
widget.decoration.image != null ? Icons.image_outlined : Icons.hide_image_outlined,
),
title: const Text('Image'),
),
if (widget.decoration.image != null)
ListTile(
enabled: widget.decoration.image != null,
leading: const Icon(Icons.layers_outlined),
title: const Text('Image position'),
trailing: PopupMenuButton(
onSelected: changeImagePosition,
initialValue: widget.decoration.image?.position,
itemBuilder: (context) {
return [
const PopupMenuItem(
value: PrettyQrDecorationImagePosition.embedded,
child: Text('Embedded'),
),
const PopupMenuItem(
value: PrettyQrDecorationImagePosition.foreground,
child: Text('Foreground'),
),
const PopupMenuItem(
value: PrettyQrDecorationImagePosition.background,
child: Text('Background'),
),
];
},
),
),
],
);
}
@protected
void changeShape(
final Type type,
) {
var shape = widget.decoration.shape;
if (shape.runtimeType == type) return;
if (shape is PrettyQrSmoothSymbol) {
shape = PrettyQrRoundedSymbol(color: shapeColor);
} else if (shape is PrettyQrRoundedSymbol) {
shape = PrettyQrSmoothSymbol(color: shapeColor);
}
widget.onChanged?.call(widget.decoration.copyWith(shape: shape));
}
@protected
void toggleColor() {
var shape = widget.decoration.shape;
var color = shapeColor != Colors.black ? Colors.black : Theme.of(context).colorScheme.secondary;
if (shape is PrettyQrSmoothSymbol) {
shape = PrettyQrSmoothSymbol(
color: color,
roundFactor: shape.roundFactor,
);
} else if (shape is PrettyQrRoundedSymbol) {
shape = PrettyQrRoundedSymbol(
color: color,
borderRadius: shape.borderRadius,
);
}
widget.onChanged?.call(widget.decoration.copyWith(shape: shape));
}
@protected
void toggleRoundedCorners() {
var shape = widget.decoration.shape;
if (shape is PrettyQrSmoothSymbol) {
shape = PrettyQrSmoothSymbol(
color: shape.color,
roundFactor: isRoundedBorders ? 0 : 1,
);
} else if (shape is PrettyQrRoundedSymbol) {
shape = PrettyQrRoundedSymbol(
color: shape.color,
borderRadius:
isRoundedBorders ? BorderRadius.zero : const BorderRadius.all(Radius.circular(10)),
);
}
widget.onChanged?.call(widget.decoration.copyWith(shape: shape));
}
@protected
void toggleImage() {
const defaultImage = _PrettyQrSettings.kDefaultPrettyQrDecorationImage;
final image = widget.decoration.image != null ? null : defaultImage;
widget.onChanged?.call(PrettyQrDecoration(image: image, shape: widget.decoration.shape));
}
@protected
void changeImagePosition(
final PrettyQrDecorationImagePosition value,
) {
final image = widget.decoration.image?.copyWith(position: value);
widget.onChanged?.call(widget.decoration.copyWith(image: image));
}
}