feat(proj): init
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:please_pay_me/theme/theme.dart';
|
||||
import 'package:please_pay_me/ui/ui.dart';
|
||||
import 'package:please_pay_me_widgetbook/knobs/common_knobs.dart';
|
||||
import 'package:please_pay_me_widgetbook/support/preview.dart';
|
||||
import 'package:widgetbook/widgetbook.dart';
|
||||
|
||||
WidgetbookComponent buttonsComponent() {
|
||||
return WidgetbookComponent(
|
||||
name: 'AppButton',
|
||||
useCases: [
|
||||
WidgetbookUseCase(
|
||||
name: 'Playground',
|
||||
builder: (context) {
|
||||
return IosPreview(
|
||||
stretch: true,
|
||||
child: AppButton(
|
||||
label: knobText(context, label: 'Label', initialValue: 'Сохранить'),
|
||||
style: knobEnum(
|
||||
context,
|
||||
label: 'Style',
|
||||
values: AppButtonStyle.values,
|
||||
initial: AppButtonStyle.filled,
|
||||
),
|
||||
size: knobEnum(
|
||||
context,
|
||||
label: 'Size',
|
||||
values: AppButtonSize.values,
|
||||
initial: AppButtonSize.large,
|
||||
),
|
||||
expanded: knobBool(context, label: 'Expanded', initialValue: true),
|
||||
loading: knobBool(context, label: 'Loading'),
|
||||
icon: knobBool(context, label: 'Icon') ? CupertinoIcons.plus : null,
|
||||
onPressed:
|
||||
knobBool(context, label: 'Enabled', initialValue: true) ? () {} : null,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
WidgetbookUseCase(
|
||||
name: 'All styles',
|
||||
builder: (context) {
|
||||
return IosPreview(
|
||||
stretch: true,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
for (final style in AppButtonStyle.values) ...[
|
||||
AppButton(label: style.name, style: style, onPressed: () {}),
|
||||
const SizedBox(height: AppSpacing.s3),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
WidgetbookUseCase(
|
||||
name: 'Sizes',
|
||||
builder: (context) {
|
||||
return IosPreview.centered(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
for (final size in AppButtonSize.values) ...[
|
||||
AppButton(
|
||||
label: 'Размер ${size.name}',
|
||||
size: size,
|
||||
expanded: false,
|
||||
onPressed: () {},
|
||||
),
|
||||
const SizedBox(height: AppSpacing.s3),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:please_pay_me/theme/theme.dart';
|
||||
import 'package:please_pay_me/ui/ui.dart';
|
||||
import 'package:please_pay_me_widgetbook/knobs/common_knobs.dart';
|
||||
import 'package:please_pay_me_widgetbook/support/preview.dart';
|
||||
import 'package:widgetbook/widgetbook.dart';
|
||||
|
||||
const _icons = <IconData>[
|
||||
CupertinoIcons.house_fill,
|
||||
CupertinoIcons.cart_fill,
|
||||
CupertinoIcons.bag_fill,
|
||||
CupertinoIcons.money_rubl_circle_fill,
|
||||
CupertinoIcons.chart_pie_fill,
|
||||
CupertinoIcons.calendar,
|
||||
CupertinoIcons.bell_fill,
|
||||
CupertinoIcons.gear_alt_fill,
|
||||
CupertinoIcons.person_fill,
|
||||
CupertinoIcons.creditcard_fill,
|
||||
];
|
||||
|
||||
WidgetbookComponent iconsComponent() {
|
||||
return WidgetbookComponent(
|
||||
name: 'Icons',
|
||||
useCases: [
|
||||
WidgetbookUseCase(
|
||||
name: 'Glyphs',
|
||||
builder: (context) {
|
||||
final size = knobDouble(context, label: 'Size', initialValue: 24, min: 12, max: 48);
|
||||
final tint = knobTint(context);
|
||||
return IosPreview(
|
||||
child: Wrap(
|
||||
spacing: AppSpacing.s5,
|
||||
runSpacing: AppSpacing.s5,
|
||||
alignment: WrapAlignment.center,
|
||||
children: [
|
||||
for (final icon in _icons) AppIcon(icon, size: size, color: tint),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
WidgetbookUseCase(
|
||||
name: 'Badges',
|
||||
builder: (context) {
|
||||
return IosPreview(
|
||||
child: Wrap(
|
||||
spacing: AppSpacing.s4,
|
||||
runSpacing: AppSpacing.s4,
|
||||
alignment: WrapAlignment.center,
|
||||
children: [
|
||||
for (final (index, icon) in _icons.indexed)
|
||||
AppIconBadge(
|
||||
icon: icon,
|
||||
color: switch (index % 4) {
|
||||
0 => AppColors.accent,
|
||||
1 => AppColors.systemRed,
|
||||
2 => AppColors.systemOrange,
|
||||
_ => AppColors.systemGray,
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:please_pay_me/theme/theme.dart';
|
||||
import 'package:please_pay_me/ui/ui.dart';
|
||||
import 'package:please_pay_me_widgetbook/knobs/common_knobs.dart';
|
||||
import 'package:please_pay_me_widgetbook/support/preview.dart';
|
||||
import 'package:widgetbook/widgetbook.dart';
|
||||
|
||||
WidgetbookComponent textFieldsComponent() {
|
||||
return WidgetbookComponent(
|
||||
name: 'AppTextField',
|
||||
useCases: [
|
||||
WidgetbookUseCase(
|
||||
name: 'Playground',
|
||||
builder: (context) {
|
||||
final error = knobText(context, label: 'Error', initialValue: '');
|
||||
return IosPreview(
|
||||
stretch: true,
|
||||
padding: const EdgeInsets.all(AppSpacing.s4),
|
||||
child: AppTextField(
|
||||
label: knobText(context, label: 'Label', initialValue: 'Сумма'),
|
||||
placeholder: knobText(context, label: 'Placeholder', initialValue: '0 ₽'),
|
||||
enabled: knobBool(context, label: 'Enabled', initialValue: true),
|
||||
obscureText: knobBool(context, label: 'Obscure'),
|
||||
clearable: knobBool(context, label: 'Clear button', initialValue: true),
|
||||
prefixIcon: knobBool(context, label: 'Prefix icon')
|
||||
? CupertinoIcons.search
|
||||
: null,
|
||||
errorText: error.isEmpty ? null : error,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
WidgetbookUseCase(
|
||||
name: 'Form group',
|
||||
builder: (context) {
|
||||
return const IosPreview(
|
||||
stretch: true,
|
||||
padding: EdgeInsets.all(AppSpacing.s4),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
AppTextField(label: 'Название', placeholder: 'Продукты'),
|
||||
SizedBox(height: AppSpacing.s4),
|
||||
AppTextField(
|
||||
label: 'Сумма',
|
||||
placeholder: '0 ₽',
|
||||
keyboardType: TextInputType.number,
|
||||
),
|
||||
SizedBox(height: AppSpacing.s4),
|
||||
AppTextField(
|
||||
label: 'Комментарий',
|
||||
placeholder: 'Необязательно',
|
||||
errorText: 'Слишком длинный комментарий',
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:please_pay_me/theme/theme.dart';
|
||||
import 'package:please_pay_me/ui/ui.dart';
|
||||
import 'package:please_pay_me_widgetbook/knobs/common_knobs.dart';
|
||||
import 'package:please_pay_me_widgetbook/support/preview.dart';
|
||||
import 'package:widgetbook/widgetbook.dart';
|
||||
|
||||
WidgetbookComponent typographyComponent() {
|
||||
return WidgetbookComponent(
|
||||
name: 'Typography',
|
||||
useCases: [
|
||||
WidgetbookUseCase(
|
||||
name: 'iOS scale',
|
||||
builder: (context) {
|
||||
final sample = knobText(context, label: 'Sample', initialValue: 'Бюджет на неделю');
|
||||
return IosPreview(
|
||||
stretch: true,
|
||||
padding: const EdgeInsets.all(AppSpacing.s4),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
AppText.largeTitle(sample),
|
||||
const SizedBox(height: AppSpacing.s3),
|
||||
AppText.title(sample),
|
||||
const SizedBox(height: AppSpacing.s3),
|
||||
AppText.headline(sample),
|
||||
const SizedBox(height: AppSpacing.s3),
|
||||
AppText.body(sample),
|
||||
const SizedBox(height: AppSpacing.s3),
|
||||
AppText.callout(sample),
|
||||
const SizedBox(height: AppSpacing.s3),
|
||||
AppText.subhead(sample),
|
||||
const SizedBox(height: AppSpacing.s3),
|
||||
AppText.footnote(sample),
|
||||
const SizedBox(height: AppSpacing.s3),
|
||||
AppText.caption(sample),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
WidgetbookUseCase(
|
||||
name: 'Section header',
|
||||
builder: (context) {
|
||||
return IosPreview(
|
||||
stretch: true,
|
||||
child: AppListSection(
|
||||
header: knobText(context, label: 'Header', initialValue: 'Настройки'),
|
||||
footer: knobText(
|
||||
context,
|
||||
label: 'Footer',
|
||||
initialValue: 'Пояснение под группой, как в iOS Settings.',
|
||||
),
|
||||
children: const [
|
||||
AppListTile(title: 'Строка', value: 'Значение'),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:please_pay_me/theme/theme.dart';
|
||||
import 'package:please_pay_me/ui/ui.dart';
|
||||
import 'package:please_pay_me_widgetbook/knobs/common_knobs.dart';
|
||||
import 'package:please_pay_me_widgetbook/support/preview.dart';
|
||||
import 'package:widgetbook/widgetbook.dart';
|
||||
|
||||
WidgetbookComponent progressComponent() {
|
||||
return WidgetbookComponent(
|
||||
name: 'Progress',
|
||||
useCases: [
|
||||
WidgetbookUseCase(
|
||||
name: 'Activity indicator',
|
||||
builder: (context) {
|
||||
return IosPreview.centered(
|
||||
child: AppSpinner(
|
||||
radius: knobDouble(context, label: 'Radius', initialValue: 14, min: 6, max: 28),
|
||||
color: knobTint(context),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
WidgetbookUseCase(
|
||||
name: 'Progress bar',
|
||||
builder: (context) {
|
||||
return IosPreview(
|
||||
stretch: true,
|
||||
padding: const EdgeInsets.all(AppSpacing.s4),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
AppProgressBar(
|
||||
value: knobDouble(context, label: 'Value', initialValue: 0.42),
|
||||
color: knobTint(context),
|
||||
height: knobDouble(context, label: 'Height', initialValue: 4, min: 2, max: 12),
|
||||
),
|
||||
const SizedBox(height: AppSpacing.s4),
|
||||
const AppProgressBar(value: 0.15, color: AppColors.systemRed),
|
||||
const SizedBox(height: AppSpacing.s4),
|
||||
const AppProgressBar(value: 1, color: AppColors.systemGreen),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import 'package:please_pay_me/ui/ui.dart';
|
||||
import 'package:please_pay_me_widgetbook/knobs/common_knobs.dart';
|
||||
import 'package:please_pay_me_widgetbook/support/preview.dart';
|
||||
import 'package:widgetbook/widgetbook.dart';
|
||||
|
||||
WidgetbookComponent skeletonsComponent() {
|
||||
return WidgetbookComponent(
|
||||
name: 'AppSkeleton',
|
||||
useCases: [
|
||||
WidgetbookUseCase(
|
||||
name: 'Block',
|
||||
builder: (context) {
|
||||
return IosPreview.centered(
|
||||
child: AppSkeleton(
|
||||
width: knobDouble(context, label: 'Width', initialValue: 200, min: 40, max: 320),
|
||||
height: knobDouble(context, label: 'Height', initialValue: 16, min: 8, max: 80),
|
||||
radius: knobDouble(context, label: 'Radius', initialValue: 6, min: 0, max: 24),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
WidgetbookUseCase(
|
||||
name: 'List loading',
|
||||
builder: (context) {
|
||||
final rows = knobInt(context, label: 'Rows', initialValue: 4, min: 1, max: 8);
|
||||
return IosPreview(
|
||||
stretch: true,
|
||||
child: AppListSection(
|
||||
header: 'Загрузка',
|
||||
separatorIndent: 60,
|
||||
children: List.generate(rows, (_) => const AppSkeletonRow()),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:please_pay_me/ui/ui.dart';
|
||||
import 'package:please_pay_me_widgetbook/knobs/common_knobs.dart';
|
||||
import 'package:please_pay_me_widgetbook/support/preview.dart';
|
||||
import 'package:widgetbook/widgetbook.dart';
|
||||
|
||||
WidgetbookComponent toastsComponent() {
|
||||
return WidgetbookComponent(
|
||||
name: 'AppToast',
|
||||
useCases: [
|
||||
WidgetbookUseCase(
|
||||
name: 'Static',
|
||||
builder: (context) {
|
||||
return IosPreview.centered(
|
||||
child: AppToast(
|
||||
message: knobText(context, label: 'Message', initialValue: 'Трата сохранена'),
|
||||
tint: knobTint(context),
|
||||
icon: knobBool(context, label: 'Icon', initialValue: true)
|
||||
? CupertinoIcons.check_mark_circled_solid
|
||||
: null,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
WidgetbookUseCase(
|
||||
name: 'Trigger',
|
||||
builder: (context) {
|
||||
return IosPreview(
|
||||
stretch: true,
|
||||
child: AppButton(
|
||||
label: 'Показать toast',
|
||||
onPressed: () => showAppToast(
|
||||
context,
|
||||
message: knobText(
|
||||
context,
|
||||
label: 'Message',
|
||||
initialValue: 'Трата сохранена',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:please_pay_me/theme/theme.dart';
|
||||
import 'package:please_pay_me/ui/ui.dart';
|
||||
import 'package:please_pay_me_widgetbook/knobs/common_knobs.dart';
|
||||
import 'package:please_pay_me_widgetbook/support/preview.dart';
|
||||
import 'package:widgetbook/widgetbook.dart';
|
||||
|
||||
WidgetbookComponent avatarsComponent() {
|
||||
return WidgetbookComponent(
|
||||
name: 'AppAvatar',
|
||||
useCases: [
|
||||
WidgetbookUseCase(
|
||||
name: 'Playground',
|
||||
builder: (context) {
|
||||
final initials = knobText(context, label: 'Initials', initialValue: 'ВА');
|
||||
return IosPreview.centered(
|
||||
child: AppAvatar(
|
||||
initials: knobBool(context, label: 'Use initials', initialValue: true)
|
||||
? initials
|
||||
: null,
|
||||
radius: knobDouble(context, label: 'Radius', initialValue: 32, min: 12, max: 56),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
WidgetbookUseCase(
|
||||
name: 'Sizes',
|
||||
builder: (context) {
|
||||
return const IosPreview.centered(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
AppAvatar(initials: 'А', radius: 16),
|
||||
SizedBox(width: AppSpacing.s4),
|
||||
AppAvatar(initials: 'ВА', radius: 22),
|
||||
SizedBox(width: AppSpacing.s4),
|
||||
AppAvatar(radius: 32),
|
||||
SizedBox(width: AppSpacing.s4),
|
||||
AppAvatar(initials: 'ППМ', radius: 44),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:please_pay_me/theme/theme.dart';
|
||||
import 'package:please_pay_me/ui/ui.dart';
|
||||
import 'package:please_pay_me_widgetbook/knobs/common_knobs.dart';
|
||||
import 'package:please_pay_me_widgetbook/support/preview.dart';
|
||||
import 'package:widgetbook/widgetbook.dart';
|
||||
|
||||
WidgetbookComponent cardsComponent() {
|
||||
return WidgetbookComponent(
|
||||
name: 'AppCard',
|
||||
useCases: [
|
||||
WidgetbookUseCase(
|
||||
name: 'Playground',
|
||||
builder: (context) {
|
||||
final subtitle = knobText(context, label: 'Subtitle', initialValue: 'До 25 сентября');
|
||||
return IosPreview(
|
||||
stretch: true,
|
||||
child: AppCard(
|
||||
title: knobText(context, label: 'Title', initialValue: 'Бюджет'),
|
||||
subtitle: subtitle.isEmpty ? null : subtitle,
|
||||
onTap: knobBool(context, label: 'Tappable') ? () {} : null,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
AppText.largeTitle(
|
||||
knobText(context, label: 'Amount', initialValue: '18 420 ₽'),
|
||||
),
|
||||
const SizedBox(height: AppSpacing.s4),
|
||||
AppProgressBar(
|
||||
value: knobDouble(context, label: 'Progress', initialValue: 0.42),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
WidgetbookUseCase(
|
||||
name: 'Metrics row',
|
||||
builder: (context) {
|
||||
return const IosPreview(
|
||||
stretch: true,
|
||||
child: AppCard(
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
AppText.footnote('Доход'),
|
||||
AppText.title('64 000 ₽'),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
AppText.footnote('Расход'),
|
||||
AppText.title('45 580 ₽', color: AppColors.systemRed),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:please_pay_me/theme/theme.dart';
|
||||
import 'package:please_pay_me/ui/ui.dart';
|
||||
import 'package:please_pay_me_widgetbook/knobs/common_knobs.dart';
|
||||
import 'package:please_pay_me_widgetbook/support/preview.dart';
|
||||
import 'package:widgetbook/widgetbook.dart';
|
||||
|
||||
WidgetbookComponent chipsComponent() {
|
||||
return WidgetbookComponent(
|
||||
name: 'AppChip',
|
||||
useCases: [
|
||||
WidgetbookUseCase(
|
||||
name: 'Playground',
|
||||
builder: (context) {
|
||||
return IosPreview.centered(
|
||||
child: AppChip(
|
||||
label: knobText(context, label: 'Label', initialValue: 'Еда'),
|
||||
selected: knobBool(context, label: 'Selected'),
|
||||
icon: knobBool(context, label: 'Icon') ? CupertinoIcons.tag_fill : null,
|
||||
onPressed: () {},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
WidgetbookUseCase(
|
||||
name: 'Filter row',
|
||||
builder: (context) {
|
||||
final selected = knobInt(context, label: 'Selected index', min: 0, max: 3);
|
||||
const labels = ['Все', 'Еда', 'Транспорт', 'Подписки'];
|
||||
return IosPreview.centered(
|
||||
child: Wrap(
|
||||
spacing: AppSpacing.s2,
|
||||
runSpacing: AppSpacing.s2,
|
||||
alignment: WrapAlignment.center,
|
||||
children: [
|
||||
for (final (index, label) in labels.indexed)
|
||||
AppChip(label: label, selected: index == selected, onPressed: () {}),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:please_pay_me/theme/theme.dart';
|
||||
import 'package:please_pay_me/ui/ui.dart';
|
||||
import 'package:please_pay_me_widgetbook/knobs/common_knobs.dart';
|
||||
import 'package:please_pay_me_widgetbook/knobs/state_knobs.dart';
|
||||
import 'package:please_pay_me_widgetbook/support/preview.dart';
|
||||
import 'package:widgetbook/widgetbook.dart';
|
||||
|
||||
WidgetbookComponent listTilesComponent() {
|
||||
return WidgetbookComponent(
|
||||
name: 'AppListTile',
|
||||
useCases: [
|
||||
WidgetbookUseCase(
|
||||
name: 'Playground',
|
||||
builder: (context) {
|
||||
final subtitle = knobText(context, label: 'Subtitle', initialValue: 'Супермаркет');
|
||||
final value = knobText(context, label: 'Value', initialValue: '−1 840 ₽');
|
||||
return IosPreview(
|
||||
stretch: true,
|
||||
child: AppListSection(
|
||||
separatorIndent: 60,
|
||||
children: [
|
||||
AppListTile(
|
||||
leading: knobBool(context, label: 'Leading badge', initialValue: true)
|
||||
? const AppIconBadge(icon: CupertinoIcons.cart_fill)
|
||||
: null,
|
||||
title: knobText(context, label: 'Title', initialValue: 'Продукты'),
|
||||
subtitle: subtitle.isEmpty ? null : subtitle,
|
||||
value: value.isEmpty ? null : value,
|
||||
destructive: knobBool(context, label: 'Destructive'),
|
||||
showChevron: knobBool(context, label: 'Chevron', initialValue: true),
|
||||
onTap: knobBool(context, label: 'Tappable', initialValue: true) ? () {} : null,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
WidgetbookUseCase(
|
||||
name: 'Grouped section',
|
||||
builder: (context) {
|
||||
final state = knobAsyncState(context);
|
||||
return IosPreview(
|
||||
stretch: true,
|
||||
child: AppListSection(
|
||||
header: 'Сегодня',
|
||||
footer: 'Свайп по строке открывает действия.',
|
||||
separatorIndent: 60,
|
||||
children: [
|
||||
wrapAsyncState(
|
||||
context: context,
|
||||
state: state,
|
||||
builder: () => const Column(
|
||||
children: [
|
||||
AppListTile(
|
||||
leading: AppIconBadge(icon: CupertinoIcons.cart_fill),
|
||||
title: 'Продукты',
|
||||
subtitle: 'Супермаркет',
|
||||
value: '−1 840 ₽',
|
||||
),
|
||||
AppListTile(
|
||||
leading: AppIconBadge(
|
||||
icon: CupertinoIcons.car_fill,
|
||||
color: AppColors.systemOrange,
|
||||
),
|
||||
title: 'Такси',
|
||||
subtitle: 'Транспорт',
|
||||
value: '−420 ₽',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:please_pay_me/theme/theme.dart';
|
||||
import 'package:please_pay_me/ui/ui.dart';
|
||||
import 'package:please_pay_me_widgetbook/knobs/common_knobs.dart';
|
||||
import 'package:please_pay_me_widgetbook/support/preview.dart';
|
||||
import 'package:widgetbook/widgetbook.dart';
|
||||
|
||||
WidgetbookComponent switchesComponent() {
|
||||
return WidgetbookComponent(
|
||||
name: 'AppSwitchRow',
|
||||
useCases: [
|
||||
WidgetbookUseCase(
|
||||
name: 'Playground',
|
||||
builder: (context) {
|
||||
final subtitle = knobText(context, label: 'Subtitle', initialValue: '');
|
||||
return IosPreview(
|
||||
stretch: true,
|
||||
child: AppListSection(
|
||||
separatorIndent: 60,
|
||||
children: [
|
||||
AppSwitchRow(
|
||||
leading: knobBool(context, label: 'Leading badge', initialValue: true)
|
||||
? const AppIconBadge(
|
||||
icon: CupertinoIcons.bell_fill,
|
||||
color: AppColors.systemRed,
|
||||
)
|
||||
: null,
|
||||
title: knobText(context, label: 'Title', initialValue: 'Уведомления'),
|
||||
subtitle: subtitle.isEmpty ? null : subtitle,
|
||||
value: knobBool(context, label: 'Value', initialValue: true),
|
||||
onChanged: knobBool(context, label: 'Enabled', initialValue: true)
|
||||
? (_) {}
|
||||
: null,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
WidgetbookUseCase(
|
||||
name: 'Settings group',
|
||||
builder: (context) {
|
||||
return IosPreview(
|
||||
stretch: true,
|
||||
child: AppListSection(
|
||||
header: 'Настройки',
|
||||
footer: 'Push приходят за час до дедлайна бюджета.',
|
||||
separatorIndent: 60,
|
||||
children: [
|
||||
AppSwitchRow(
|
||||
leading: const AppIconBadge(
|
||||
icon: CupertinoIcons.bell_fill,
|
||||
color: AppColors.systemRed,
|
||||
),
|
||||
title: 'Уведомления',
|
||||
value: true,
|
||||
onChanged: (_) {},
|
||||
),
|
||||
AppSwitchRow(
|
||||
leading: const AppIconBadge(
|
||||
icon: CupertinoIcons.lock_fill,
|
||||
color: AppColors.systemGray,
|
||||
),
|
||||
title: 'Face ID',
|
||||
value: false,
|
||||
onChanged: (_) {},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:please_pay_me/theme/theme.dart';
|
||||
import 'package:please_pay_me/ui/ui.dart';
|
||||
import 'package:please_pay_me_widgetbook/knobs/common_knobs.dart';
|
||||
import 'package:please_pay_me_widgetbook/support/preview.dart';
|
||||
import 'package:widgetbook/widgetbook.dart';
|
||||
|
||||
WidgetbookComponent dialogsComponent() {
|
||||
return WidgetbookComponent(
|
||||
name: 'AppAlert',
|
||||
useCases: [
|
||||
WidgetbookUseCase(
|
||||
name: 'Alert',
|
||||
builder: (context) {
|
||||
final message = knobText(
|
||||
context,
|
||||
label: 'Message',
|
||||
initialValue: 'Операция будет удалена без возможности восстановления.',
|
||||
);
|
||||
return IosPreview.centered(
|
||||
child: AppAlert(
|
||||
title: knobText(context, label: 'Title', initialValue: 'Удалить трату?'),
|
||||
message: message.isEmpty ? null : message,
|
||||
confirmLabel: knobText(context, label: 'Confirm', initialValue: 'Удалить'),
|
||||
cancelLabel: knobBool(context, label: 'Cancel button', initialValue: true)
|
||||
? 'Отмена'
|
||||
: null,
|
||||
destructive: knobBool(context, label: 'Destructive', initialValue: true),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
WidgetbookUseCase(
|
||||
name: 'Triggers',
|
||||
builder: (context) {
|
||||
return IosPreview(
|
||||
stretch: true,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
AppButton(
|
||||
label: 'Показать alert',
|
||||
onPressed: () => showAppAlert(
|
||||
context: context,
|
||||
title: 'Удалить трату?',
|
||||
message: 'Действие необратимо.',
|
||||
confirmLabel: 'Удалить',
|
||||
cancelLabel: 'Отмена',
|
||||
destructive: true,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: AppSpacing.s3),
|
||||
AppButton(
|
||||
label: 'Показать action sheet',
|
||||
style: AppButtonStyle.gray,
|
||||
onPressed: () => showAppActionSheet(
|
||||
context: context,
|
||||
title: 'Операция',
|
||||
actions: const [
|
||||
AppActionSheetAction(label: 'Редактировать', isDefault: true),
|
||||
AppActionSheetAction(label: 'Дублировать'),
|
||||
AppActionSheetAction(label: 'Удалить', destructive: true),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:please_pay_me/theme/theme.dart';
|
||||
import 'package:please_pay_me/ui/ui.dart';
|
||||
import 'package:please_pay_me_widgetbook/knobs/common_knobs.dart';
|
||||
import 'package:widgetbook/widgetbook.dart';
|
||||
|
||||
WidgetbookComponent navBarComponent() {
|
||||
return WidgetbookComponent(
|
||||
name: 'AppNavBar',
|
||||
useCases: [
|
||||
WidgetbookUseCase(
|
||||
name: 'Playground',
|
||||
builder: (context) {
|
||||
final subtitle = knobText(context, label: 'Subtitle', initialValue: 'До 25 сентября');
|
||||
return CupertinoPageScaffold(
|
||||
backgroundColor: AppColors.of(context, AppColors.groupedBackground),
|
||||
navigationBar: AppNavBar(
|
||||
title: knobText(context, label: 'Title', initialValue: 'Бюджет'),
|
||||
subtitle: subtitle.isEmpty ? null : subtitle,
|
||||
previousPageTitle:
|
||||
knobBool(context, label: 'Back button', initialValue: true) ? 'Назад' : null,
|
||||
transparent: knobBool(context, label: 'Transparent'),
|
||||
trailing: knobBool(context, label: 'Trailing action', initialValue: true)
|
||||
? CupertinoButton(
|
||||
padding: EdgeInsets.zero,
|
||||
minimumSize: Size.zero,
|
||||
onPressed: () {},
|
||||
child: const AppIcon(
|
||||
CupertinoIcons.ellipsis_circle,
|
||||
color: AppColors.accent,
|
||||
),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
child: const SafeArea(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(AppSpacing.s4),
|
||||
child: AppText.subhead('Контент под навигационной панелью'),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
WidgetbookUseCase(
|
||||
name: 'Large title',
|
||||
builder: (context) {
|
||||
return CupertinoPageScaffold(
|
||||
backgroundColor: AppColors.of(context, AppColors.groupedBackground),
|
||||
child: CustomScrollView(
|
||||
slivers: [
|
||||
AppLargeNavBar(
|
||||
title: knobText(context, label: 'Title', initialValue: 'Журнал'),
|
||||
trailing: CupertinoButton(
|
||||
padding: EdgeInsets.zero,
|
||||
minimumSize: Size.zero,
|
||||
onPressed: () {},
|
||||
child: const AppIcon(
|
||||
CupertinoIcons.add_circled,
|
||||
color: AppColors.accent,
|
||||
),
|
||||
),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: AppListSection(
|
||||
header: 'Сегодня',
|
||||
separatorIndent: 60,
|
||||
children: const [
|
||||
AppListTile(
|
||||
leading: AppIconBadge(icon: CupertinoIcons.cart_fill),
|
||||
title: 'Продукты',
|
||||
value: '−1 840 ₽',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:please_pay_me/theme/theme.dart';
|
||||
import 'package:please_pay_me/ui/ui.dart';
|
||||
import 'package:please_pay_me_widgetbook/knobs/common_knobs.dart';
|
||||
import 'package:please_pay_me_widgetbook/support/preview.dart';
|
||||
import 'package:widgetbook/widgetbook.dart';
|
||||
|
||||
WidgetbookComponent segmentedControlComponent() {
|
||||
return WidgetbookComponent(
|
||||
name: 'AppSegmentedControl',
|
||||
useCases: [
|
||||
WidgetbookUseCase(
|
||||
name: 'Playground',
|
||||
builder: (context) {
|
||||
final labels = knobText(
|
||||
context,
|
||||
label: 'Labels (comma separated)',
|
||||
initialValue: 'Все,Расходы,Доходы',
|
||||
).split(',').where((e) => e.trim().isNotEmpty).toList();
|
||||
|
||||
final safeLabels = labels.isEmpty ? ['Все'] : labels;
|
||||
|
||||
return IosPreview(
|
||||
stretch: true,
|
||||
child: _StatefulSegments(
|
||||
labels: safeLabels,
|
||||
initialIndex: knobInt(
|
||||
context,
|
||||
label: 'Initial index',
|
||||
max: safeLabels.length - 1,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
WidgetbookUseCase(
|
||||
name: 'In screen header',
|
||||
builder: (context) {
|
||||
return CupertinoPageScaffold(
|
||||
backgroundColor: AppColors.of(context, AppColors.groupedBackground),
|
||||
navigationBar: const AppNavBar(title: 'Журнал'),
|
||||
child: SafeArea(
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(height: AppSpacing.s4),
|
||||
const _StatefulSegments(labels: ['Неделя', 'Месяц', 'Год']),
|
||||
const SizedBox(height: AppSpacing.s5),
|
||||
AppListSection(
|
||||
children: const [
|
||||
AppListTile(title: 'Итого', value: '45 580 ₽'),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
class _StatefulSegments extends StatefulWidget {
|
||||
const _StatefulSegments({required this.labels, this.initialIndex = 0});
|
||||
|
||||
final List<String> labels;
|
||||
final int initialIndex;
|
||||
|
||||
@override
|
||||
State<_StatefulSegments> createState() => _StatefulSegmentsState();
|
||||
}
|
||||
|
||||
class _StatefulSegmentsState extends State<_StatefulSegments> {
|
||||
late int _index = widget.initialIndex;
|
||||
|
||||
@override
|
||||
void didUpdateWidget(_StatefulSegments oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (oldWidget.initialIndex != widget.initialIndex ||
|
||||
_index >= widget.labels.length) {
|
||||
_index = widget.initialIndex.clamp(0, widget.labels.length - 1);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AppSegmentedControl(
|
||||
labels: widget.labels,
|
||||
index: _index,
|
||||
onChanged: (i) => setState(() => _index = i),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:please_pay_me/theme/theme.dart';
|
||||
import 'package:please_pay_me/ui/ui.dart';
|
||||
import 'package:please_pay_me_widgetbook/knobs/common_knobs.dart';
|
||||
import 'package:widgetbook/widgetbook.dart';
|
||||
|
||||
const _items = [
|
||||
AppTabItem(icon: CupertinoIcons.list_bullet, label: 'Журнал'),
|
||||
AppTabItem(icon: CupertinoIcons.chart_pie, label: 'Бюджет'),
|
||||
AppTabItem(
|
||||
icon: CupertinoIcons.person,
|
||||
activeIcon: CupertinoIcons.person_fill,
|
||||
label: 'Профиль',
|
||||
),
|
||||
];
|
||||
|
||||
WidgetbookComponent tabBarComponent() {
|
||||
return WidgetbookComponent(
|
||||
name: 'AppTabBar',
|
||||
useCases: [
|
||||
WidgetbookUseCase(
|
||||
name: 'Playground',
|
||||
builder: (context) {
|
||||
final index = knobInt(context, label: 'Current index', min: 0, max: 2);
|
||||
return ColoredBox(
|
||||
color: AppColors.of(context, AppColors.groupedBackground),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
AppTabBar(items: _items, currentIndex: index, onTap: (_) {}),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
WidgetbookUseCase(
|
||||
name: 'In scaffold',
|
||||
builder: (context) {
|
||||
return CupertinoTabScaffold(
|
||||
tabBar: AppTabBar(items: _items, currentIndex: 0, onTap: (_) {}),
|
||||
tabBuilder: (context, index) => CupertinoTabView(
|
||||
builder: (context) => CupertinoPageScaffold(
|
||||
backgroundColor: AppColors.of(context, AppColors.groupedBackground),
|
||||
navigationBar: AppNavBar(title: _items[index].label),
|
||||
child: Center(child: AppText.body(_items[index].label)),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
import 'package:please_pay_me/app/home_tabs.dart';
|
||||
import 'package:please_pay_me/features/auth/login_screen.dart';
|
||||
import 'package:please_pay_me/features/budgets/budgets_screen.dart';
|
||||
import 'package:please_pay_me/features/journal/journal_screen.dart';
|
||||
import 'package:please_pay_me/features/overview/overview_screen.dart';
|
||||
import 'package:please_pay_me/features/profile/profile_screen.dart';
|
||||
import 'package:please_pay_me/features/splash/splash_screen.dart';
|
||||
import 'package:please_pay_me/features/work/work_screen.dart';
|
||||
import 'package:please_pay_me_widgetbook/support/demo_scope.dart';
|
||||
import 'package:widgetbook/widgetbook.dart';
|
||||
|
||||
WidgetbookComponent overviewScreenComponent() {
|
||||
return WidgetbookComponent(
|
||||
name: 'OverviewScreen',
|
||||
useCases: [
|
||||
WidgetbookUseCase(
|
||||
name: 'С активным бюджетом',
|
||||
builder: (context) => const DemoScope(child: OverviewScreen()),
|
||||
),
|
||||
WidgetbookUseCase(
|
||||
name: 'Без бюджетов',
|
||||
builder: (context) => const DemoScope(seeded: false, child: OverviewScreen()),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
WidgetbookComponent journalScreenComponent() {
|
||||
return WidgetbookComponent(
|
||||
name: 'JournalScreen',
|
||||
useCases: [
|
||||
WidgetbookUseCase(
|
||||
name: 'С операциями',
|
||||
builder: (context) => const DemoScope(child: JournalScreen()),
|
||||
),
|
||||
WidgetbookUseCase(
|
||||
name: 'Пустой',
|
||||
builder: (context) => const DemoScope(seeded: false, child: JournalScreen()),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
WidgetbookComponent budgetsScreenComponent() {
|
||||
return WidgetbookComponent(
|
||||
name: 'BudgetsScreen',
|
||||
useCases: [
|
||||
WidgetbookUseCase(
|
||||
name: 'Активные и завершённые',
|
||||
builder: (context) => const DemoScope(child: BudgetsScreen()),
|
||||
),
|
||||
WidgetbookUseCase(
|
||||
name: 'Пустой',
|
||||
builder: (context) => const DemoScope(seeded: false, child: BudgetsScreen()),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
WidgetbookComponent workScreenComponent() {
|
||||
return WidgetbookComponent(
|
||||
name: 'WorkScreen',
|
||||
useCases: [
|
||||
WidgetbookUseCase(
|
||||
name: 'С работой',
|
||||
builder: (context) => const DemoScope(child: WorkScreen()),
|
||||
),
|
||||
WidgetbookUseCase(
|
||||
name: 'Пустой',
|
||||
builder: (context) => const DemoScope(seeded: false, child: WorkScreen()),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
WidgetbookComponent profileScreenComponent() {
|
||||
return WidgetbookComponent(
|
||||
name: 'ProfileScreen',
|
||||
useCases: [
|
||||
WidgetbookUseCase(
|
||||
name: 'Демо-сессия',
|
||||
builder: (context) => const DemoScope(child: ProfileScreen()),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
WidgetbookComponent splashScreenComponent() {
|
||||
return WidgetbookComponent(
|
||||
name: 'SplashScreen',
|
||||
useCases: [
|
||||
WidgetbookUseCase(
|
||||
name: 'Запуск',
|
||||
builder: (context) => const SplashScreen(),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
WidgetbookComponent loginScreenComponent() {
|
||||
return WidgetbookComponent(
|
||||
name: 'LoginScreen',
|
||||
useCases: [
|
||||
WidgetbookUseCase(
|
||||
name: 'Вход через Telegram',
|
||||
builder: (context) => DemoScope(
|
||||
// Desktop has no WebView, so the catalog stubs the launcher to show
|
||||
// the mobile layout.
|
||||
child: LoginScreen(launchTelegramLogin: (_, __) async => null),
|
||||
),
|
||||
),
|
||||
WidgetbookUseCase(
|
||||
name: 'Вход по токену',
|
||||
builder: (context) => const DemoScope(child: LoginScreen()),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
WidgetbookComponent homeTabsComponent() {
|
||||
return WidgetbookComponent(
|
||||
name: 'HomeTabs',
|
||||
useCases: [
|
||||
WidgetbookUseCase(
|
||||
name: 'Полное приложение',
|
||||
builder: (context) => const DemoScope(child: HomeTabs()),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
import 'package:please_pay_me/data/demo/demo_backend.dart';
|
||||
import 'package:please_pay_me/features/budgets/budget_form_sheet.dart';
|
||||
import 'package:please_pay_me/features/expenses/expense_form_sheet.dart';
|
||||
import 'package:please_pay_me/features/work/job_form_sheet.dart';
|
||||
import 'package:please_pay_me_widgetbook/support/demo_scope.dart';
|
||||
import 'package:widgetbook/widgetbook.dart';
|
||||
|
||||
WidgetbookComponent sheetsComponent() {
|
||||
return WidgetbookComponent(
|
||||
name: 'Формы',
|
||||
useCases: [
|
||||
WidgetbookUseCase(
|
||||
name: 'Новая трата',
|
||||
builder: (context) => DemoScope(
|
||||
child: ExpenseFormSheet(
|
||||
budgetName: 'До аванса',
|
||||
remainingToday: 1420,
|
||||
onSubmit: ({required amount, note, required spentAt}) async => null,
|
||||
),
|
||||
),
|
||||
),
|
||||
WidgetbookUseCase(
|
||||
name: 'Новый бюджет',
|
||||
builder: (context) => DemoScope(
|
||||
child: BudgetFormSheet(
|
||||
onSubmit: ({
|
||||
required name,
|
||||
required totalAmount,
|
||||
required startDate,
|
||||
required endDate,
|
||||
required resetExpenses,
|
||||
}) async =>
|
||||
null,
|
||||
),
|
||||
),
|
||||
),
|
||||
WidgetbookUseCase(
|
||||
name: 'Новая работа',
|
||||
builder: (context) => DemoScope(
|
||||
child: JobFormSheet(
|
||||
onSubmit: ({
|
||||
required name,
|
||||
required salaryAmount,
|
||||
required payDays,
|
||||
required firstPayPercent,
|
||||
required weekendPolicy,
|
||||
}) async =>
|
||||
null,
|
||||
),
|
||||
),
|
||||
),
|
||||
WidgetbookUseCase(
|
||||
name: 'Ошибка сохранения',
|
||||
builder: (context) => DemoScope(
|
||||
child: ExpenseFormSheet(
|
||||
budgetName: DemoBackend.user.displayName,
|
||||
onSubmit: ({required amount, note, required spentAt}) async =>
|
||||
'Бюджет уже завершён',
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user