Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Dial Pad #30

Merged
merged 5 commits into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @benken @mikecoomber @thelukewalton
19 changes: 7 additions & 12 deletions example/lib/home.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:zeta_example/pages/components/bottom_sheet_example.dart';
import 'package:zeta_example/pages/components/button_example.dart';
import 'package:zeta_example/pages/components/checkbox_example.dart';
import 'package:zeta_example/pages/components/chip_example.dart';
import 'package:zeta_example/pages/components/dialpad_example.dart';
import 'package:zeta_example/pages/theme/color_example.dart';
import 'package:zeta_example/pages/components/password_input_example.dart';
import 'package:zeta_example/pages/components/progress_example.dart';
Expand All @@ -32,9 +33,9 @@ final List<Component> components = [
Component(ButtonExample.name, (context) => const ButtonExample()),
Component(CheckBoxExample.name, (context) => const CheckBoxExample()),
Component(ChipExample.name, (context) => const ChipExample()),
Component(
PasswordInputExample.name, (context) => const PasswordInputExample()),
Component(ProgressExample.name, (context) => const ProgressExample())
Component(PasswordInputExample.name, (context) => const PasswordInputExample()),
Component(ProgressExample.name, (context) => const ProgressExample()),
Component(DialPadExample.name, (context) => const DialPadExample()),
];

final List<Component> theme = [
Expand Down Expand Up @@ -96,27 +97,21 @@ class _HomeState extends State<Home> {
title: Text('Widgets'),
backgroundColor: Zeta.of(context).colors.warm.shade30,
children: _components
.map((item) => ListTile(
title: Text(item.name),
onTap: () => context.go('/${item.name}')))
.map((item) => ListTile(title: Text(item.name), onTap: () => context.go('/${item.name}')))
.toList(),
),
ExpansionTile(
title: Text('Theme'),
backgroundColor: Zeta.of(context).colors.warm.shade30,
children: _theme
.map((item) => ListTile(
title: Text(item.name),
onTap: () => context.go('/${item.name}')))
.map((item) => ListTile(title: Text(item.name), onTap: () => context.go('/${item.name}')))
.toList(),
),
ExpansionTile(
title: Text('Assets'),
backgroundColor: Zeta.of(context).colors.warm.shade30,
children: _assets
.map((item) => ListTile(
title: Text(item.name),
onTap: () => context.go('/${item.name}')))
.map((item) => ListTile(title: Text(item.name), onTap: () => context.go('/${item.name}')))
.toList(),
),
],
Expand Down
95 changes: 95 additions & 0 deletions example/lib/pages/components/dialpad_example.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import 'package:flutter/material.dart';
import 'package:zeta_example/widgets.dart';
import 'package:zeta_flutter/zeta_flutter.dart';

const double _paddingSize = 40;

class DialPadExample extends StatefulWidget {
static const String name = 'DialPad';

const DialPadExample({super.key});

@override
State<DialPadExample> createState() => _DialPadExampleState();
}

class _DialPadExampleState extends State<DialPadExample> {
String number = '', text = '';

@override
Widget build(BuildContext context) {
return ExampleScaffold(
name: DialPadExample.name,
child: LayoutBuilder(builder: (context, constraints) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
width: constraints.maxWidth,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const SizedBox(width: _paddingSize),
SizedBox(
width: constraints.maxWidth - (_paddingSize * 2),
child: Text(
number,
style: ZetaTextStyles.heading3,
maxLines: 1,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center,
),
),
IconButton(
icon: Icon(Icons.backspace),
onPressed: () => number.length == 0
? null
: setState(
() => number = number.substring(0, (number.length - 1)),
),
)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const SizedBox(),
Text(
text,
style: ZetaTextStyles.heading3,
maxLines: 1,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center,
),
IconButton(
icon: Icon(Icons.backspace),
onPressed: () => text.length == 0
? null
: setState(
() => text = text.substring(0, text.length - 1),
),
)
],
),
ZetaDialPad(
onNumber: (value) => setState(() => number += value),
onText: (value) => setState(() => text += value),
),
ZetaButton.primary(
label: 'Clear',
borderType: ZetaWidgetBorder.full,
onPressed: () => setState(() => number = text = ''),
)
].divide(const SizedBox(height: ZetaSpacing.m)).toList(),
),
),
],
);
}),
);
}
}
24 changes: 5 additions & 19 deletions example/lib/pages/components/progress_example.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,7 @@ class ProgressExampleState extends State<ProgressExample> {
SizedBox(
height: 20,
),
Wrapper(
stepsCompleted: 0,
type: ZetaBarType.standard,
isThin: false,
stateChangeable: true),
Wrapper(stepsCompleted: 0, type: ZetaBarType.standard, isThin: false, stateChangeable: true),
SizedBox(
height: 20,
),
Expand Down Expand Up @@ -94,9 +90,7 @@ class _WrapperState extends State<Wrapper> {

void setLoading() {
setState(() {
type = type == ZetaBarType.buffering
? ZetaBarType.standard
: ZetaBarType.buffering;
type = type == ZetaBarType.buffering ? ZetaBarType.standard : ZetaBarType.buffering;
});
}

Expand All @@ -108,25 +102,17 @@ class _WrapperState extends State<Wrapper> {
SizedBox(
width: 400,
child: ZetaProgressBar(
progress: progress,
rounded: widget.rounded,
type: type,
isThin: widget.isThin,
label: widget.label),
progress: progress, rounded: widget.rounded, type: type, isThin: widget.isThin, label: widget.label),
),
const SizedBox(width: 40),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
widget.type != ZetaBarType.indeterminate
? FilledButton(
onPressed: increasePercentage, child: Text("Increase"))
? FilledButton(onPressed: increasePercentage, child: Text("Increase"))
: Container(),
const SizedBox(width: 40),
widget.stateChangeable
? FilledButton(
onPressed: setLoading, child: Text("Start Buffering"))
: Container()
widget.stateChangeable ? FilledButton(onPressed: setLoading, child: Text("Start Buffering")) : Container()
],
)
],
Expand Down
116 changes: 116 additions & 0 deletions example/test/dialpad_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:zeta_flutter/zeta_flutter.dart';

import 'test_components.dart';

void main() {
group('ZetaDialPad Tests', () {
testWidgets('Initializes with correct parameters', (WidgetTester tester) async {
String number = '', text = '';

Future<void> debounceWait() => tester.binding.delayed(const Duration(milliseconds: 500));

await tester.pumpWidget(
TestWidget(
screenSize: Size(1000, 1000),
widget: ZetaDialPad(
onNumber: (value) => number += value,
onText: (value) => text += value,
),
),
);
final dialPadFinder = find.byType(ZetaDialPad);
final buttonFinder = find.byType(ZetaDialPadButton);

final oneFinder = find.byWidgetPredicate((widget) => widget is ZetaDialPadButton && widget.primary == '1');
final twoFinder = find.byWidgetPredicate((widget) => widget is ZetaDialPadButton && widget.primary == '2');
final threeFinder = find.byWidgetPredicate((widget) => widget is ZetaDialPadButton && widget.primary == '3');
final starFinder = find.byWidgetPredicate((widget) => widget is ZetaDialPadButton && widget.primary == '*');
final hashFinder = find.byWidgetPredicate((widget) => widget is ZetaDialPadButton && widget.primary == '#');

final ZetaDialPad dialPad = tester.firstWidget(dialPadFinder);
final List<Widget> dialPadButtons = tester.widgetList(buttonFinder).toList();

final ZetaDialPadButton one = tester.firstWidget(oneFinder);
final ZetaDialPadButton two = tester.firstWidget(twoFinder);
final ZetaDialPadButton three = tester.firstWidget(threeFinder);

/// Dial Pad built correctly.
expect(dialPad.buttonsPerRow, 3);
expect(dialPadButtons.length, 12);

/// Dial Pad buttons built correctly.
expect(one.primary, '1');
expect(one.secondary, '');
expect(two.primary, '2');
expect(two.secondary, 'ABC');
expect(three.primary, '3');
expect(three.secondary, 'DEF');

/// Tap button with only number.
await tester.tap(oneFinder);
await tester.pump();
expect(number, '1');

/// Tap button with number and text.
await tester.tap(twoFinder);
await tester.pump();
await debounceWait();
expect(number, '12');
expect(text, 'A');

/// Tap different button.
await tester.tap(threeFinder);
await tester.pump();
await debounceWait();
expect(number, '123');
expect(text, 'AD');

/// Tap text button twice.
await tester.tap(twoFinder);
await tester.tap(twoFinder);
await tester.pump();
await debounceWait();
expect(text, 'ADB');

/// Tap text button thrice.
await tester.tap(twoFinder);
await tester.tap(twoFinder);
await tester.tap(twoFinder);
await tester.pump();
await debounceWait();
expect(text, 'ADBC');

/// Tap different text buttons to ensure debounce is cancelled.
await tester.tap(twoFinder);
await tester.tap(threeFinder);
await tester.tap(twoFinder);
await tester.pump();
await debounceWait();
expect(text, 'ADBCADA');

/// Tap text button more times than there is options to ensure it loops around correctly.
await tester.tap(threeFinder);
await tester.tap(threeFinder);
await tester.tap(threeFinder);
await tester.tap(threeFinder);
await tester.tap(threeFinder);
await tester.tap(threeFinder);
await tester.tap(oneFinder);
await tester.pump();
expect(text, 'ADBCADAF');
number = '';

/// Tap buttons with symbols
await tester.ensureVisible(starFinder);
await tester.tap(starFinder);
await tester.tap(hashFinder);
await tester.pump();
expect(number, '*#');

/// Allow all timers to end in text debounce
await debounceWait();
});
});
}
17 changes: 10 additions & 7 deletions example/web/index.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<!DOCTYPE html>
<html>

<head>
<!--
If you are serving your web app in a path other than the root, change the
Expand All @@ -18,7 +19,7 @@

<meta charset="UTF-8">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<meta name="description" content="Demonstrates how to use the zeta_flutter plugin.">
<meta name="description" content="Demonstrates how to use the zeta_flutter library.">

<!-- iOS meta tags & icons -->
<meta name="apple-mobile-web-app-capable" content="yes">
Expand All @@ -27,33 +28,35 @@
<link rel="apple-touch-icon" href="icons/Icon-192.png">

<!-- Favicon -->
<link rel="icon" type="image/png" href="favicon.png"/>
<link rel="icon" type="image/png" href="favicon.png" />

<title>zeta_flutter_example</title>
<link rel="manifest" href="manifest.json">

<script>
// The value below is injected by flutter build, do not touch.
var serviceWorkerVersion = null;
const serviceWorkerVersion = null;
</script>
<!-- This script adds the flutter initialization JS code -->
<script src="flutter.js" defer></script>
</head>

<body>
<script>
window.addEventListener('load', function(ev) {
window.addEventListener('load', function (ev) {
// Download main.dart.js
_flutter.loader.loadEntrypoint({
serviceWorker: {
serviceWorkerVersion: serviceWorkerVersion,
},
onEntrypointLoaded: function(engineInitializer) {
engineInitializer.initializeEngine().then(function(appRunner) {
onEntrypointLoaded: function (engineInitializer) {
engineInitializer.initializeEngine({ useColorEmoji: true, }).then(function (appRunner) {
appRunner.runApp();
});
}
});
});
</script>
</body>
</html>

</html>
Loading
Loading