Prepare product layout and reusable Flutter theme
Relocate the existing Astro website and preserve its assets and hosting configuration. Add the consumer/backend scaffold and themed Flutter package with consumer tests. Related to #1.
This commit is contained in:
1 parent
ef65a40213
commit
d9318053e8
46 files changed
+703
-1
No files matched your search
@@ -0,0 +1,77 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:sxchnge_theme/sxchnge_theme.dart';
|
||||
|
||||
void main() => runApp(const ThemeExample());
|
||||
|
||||
class ThemeExample extends StatelessWidget {
|
||||
const ThemeExample({super.key, this.mode = ThemeMode.system});
|
||||
|
||||
final ThemeMode mode;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => MaterialApp(
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: SxchngeTheme.light(),
|
||||
darkTheme: SxchngeTheme.dark(),
|
||||
themeMode: mode,
|
||||
home: const _Gallery(),
|
||||
);
|
||||
}
|
||||
|
||||
class _Gallery extends StatelessWidget {
|
||||
const _Gallery();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Scaffold(
|
||||
appBar: AppBar(title: const Text('sxchnge')),
|
||||
body: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 560),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Text(
|
||||
'Your next exchange',
|
||||
style: Theme.of(context).textTheme.headlineLarge,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Text(
|
||||
'Обмен без лишних шагов.\nA preview of the SXCHNGE theme.',
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
const Card(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(24),
|
||||
child: Text('Clear amounts. Clear choices.'),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
const TextField(
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Amount',
|
||||
hintText: '0.00',
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const TextField(
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Email',
|
||||
errorText: 'Enter a valid email address',
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
FilledButton(onPressed: () {}, child: const Text('Continue')),
|
||||
const SizedBox(height: 12),
|
||||
OutlinedButton(onPressed: () {}, child: const Text('Back')),
|
||||
const SizedBox(height: 12),
|
||||
const FilledButton(onPressed: null, child: Text('Unavailable')),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
name: sxchnge_theme_example
|
||||
description: Minimal consumer and component gallery for the SXCHNGE theme.
|
||||
publish_to: none
|
||||
environment:
|
||||
sdk: '>=3.13.0 <4.0.0'
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
sxchnge_theme:
|
||||
path: ../
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
flutter:
|
||||
uses-material-design: true
|
||||
@@ -0,0 +1,51 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'package:sxchnge_theme_example/main.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('consumer bundles the package font and its license', (
|
||||
tester,
|
||||
) async {
|
||||
await tester.pumpWidget(const ThemeExample());
|
||||
final manifest =
|
||||
jsonDecode(await rootBundle.loadString('FontManifest.json')) as List;
|
||||
final family = manifest.cast<Map>().singleWhere(
|
||||
(font) => font['family'] == 'packages/sxchnge_theme/Onest',
|
||||
);
|
||||
final asset = (family['fonts'] as List).first['asset'] as String;
|
||||
expect((await rootBundle.load(asset)).lengthInBytes, greaterThan(1000));
|
||||
expect(
|
||||
await rootBundle.loadString(
|
||||
'packages/sxchnge_theme/assets/fonts/OFL.txt',
|
||||
),
|
||||
contains('SIL OPEN FONT LICENSE'),
|
||||
);
|
||||
});
|
||||
|
||||
for (final mode in [ThemeMode.light, ThemeMode.dark]) {
|
||||
testWidgets(
|
||||
'$mode renders on a narrow screen with large text and accepts input',
|
||||
(tester) async {
|
||||
tester.view.physicalSize = const Size(320, 900);
|
||||
tester.view.devicePixelRatio = 1;
|
||||
tester.platformDispatcher.textScaleFactorTestValue = 2;
|
||||
addTearDown(tester.view.resetPhysicalSize);
|
||||
addTearDown(tester.view.resetDevicePixelRatio);
|
||||
addTearDown(tester.platformDispatcher.clearTextScaleFactorTestValue);
|
||||
await tester.pumpWidget(ThemeExample(mode: mode));
|
||||
await tester.pumpAndSettle();
|
||||
expect(tester.takeException(), isNull);
|
||||
await tester.enterText(find.byType(TextField).first, '125.50');
|
||||
expect(find.text('125.50'), findsOneWidget);
|
||||
await tester.ensureVisible(find.text('Continue'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(tester.takeException(), isNull);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user