diff --git a/lib/main.dart b/lib/main.dart index 58cf941..92cb0db 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,8 @@ import 'package:flutter/material.dart'; +import 'package:material_color_utilities/material_color_utilities.dart'; + +import 'res/theme.dart'; +import 'screens/metering/metering_screen.dart'; void main() { runApp(const MyApp()); @@ -12,56 +16,10 @@ class MyApp extends StatelessWidget { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( - primarySwatch: Colors.blue, - ), - home: const MyHomePage(title: 'Flutter Demo Home Page'), - ); - } -} - -class MyHomePage extends StatefulWidget { - const MyHomePage({super.key, required this.title}); - - final String title; - - @override - State createState() => _MyHomePageState(); -} - -class _MyHomePageState extends State { - int _counter = 0; - - void _incrementCounter() { - setState(() { - _counter++; - }); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(widget.title), - ), - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text( - 'You have pushed the button this many times:', - ), - Text( - '$_counter', - style: Theme.of(context).textTheme.headline4, - ), - ], - ), - ), - floatingActionButton: FloatingActionButton( - onPressed: _incrementCounter, - tooltip: 'Increment', - child: const Icon(Icons.add), + useMaterial3: true, + colorScheme: lightColorScheme, ), + home: const MeteringScreen(), ); } } diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart index 91f067e..39c568e 100644 --- a/lib/res/dimens.dart +++ b/lib/res/dimens.dart @@ -4,6 +4,7 @@ class Dimens { static const double borderRadiusM = 16; static const double borderRadiusL = 24; + static const double grid4 = 4; static const double grid8 = 8; static const double grid16 = 16; diff --git a/lib/res/theme.dart b/lib/res/theme.dart new file mode 100644 index 0000000..440eb13 --- /dev/null +++ b/lib/res/theme.dart @@ -0,0 +1,22 @@ +import 'package:flutter/material.dart'; +import 'package:material_color_utilities/material_color_utilities.dart'; + +ColorScheme get lightColorScheme { + final scheme = Scheme.light(0xFF2196f3); + return ColorScheme.light( + primary: Color(scheme.primary), + onPrimary: Color(scheme.onPrimary), + primaryContainer: Color(scheme.primaryContainer), + onPrimaryContainer: Color(scheme.onPrimaryContainer), + secondary: Color(scheme.secondary), + onSecondary: Color(scheme.onSecondary), + error: Color(scheme.error), + onError: Color(scheme.onError), + background: Color(scheme.background), + onBackground: Color(scheme.onBackground), + surface: Color.alphaBlend(Color(scheme.primary).withOpacity(0.05), Color(scheme.background)), + onSurface: Color(scheme.onSurface), + surfaceVariant: Color.alphaBlend(Color(scheme.primary).withOpacity(0.5), Color(scheme.background)), + onSurfaceVariant: Color(scheme.onSurfaceVariant), + ); +} diff --git a/lib/screens/metering/components/topbar/components/reading_container.dart b/lib/screens/metering/components/topbar/components/reading_container.dart index 22b09db..e1cf5db 100644 --- a/lib/screens/metering/components/topbar/components/reading_container.dart +++ b/lib/screens/metering/components/topbar/components/reading_container.dart @@ -58,9 +58,9 @@ class _ReadingValueBuilder extends StatelessWidget { children: [ Text( reading.label, - style: textTheme.labelLarge?.copyWith(color: Theme.of(context).colorScheme.onPrimaryContainer), + style: textTheme.labelMedium?.copyWith(color: Theme.of(context).colorScheme.onPrimaryContainer), ), - const SizedBox(height: Dimens.grid8), + const SizedBox(height: Dimens.grid4), Text( reading.value, style: textTheme.titleLarge?.copyWith(color: Theme.of(context).colorScheme.onPrimaryContainer), diff --git a/lib/screens/metering/components/topbar/topbar.dart b/lib/screens/metering/components/topbar/topbar.dart new file mode 100644 index 0000000..80bba5f --- /dev/null +++ b/lib/screens/metering/components/topbar/topbar.dart @@ -0,0 +1,139 @@ +import 'package:flutter/material.dart'; +import 'package:lightmeter/res/dimens.dart'; +import 'package:lightmeter/screens/metering/components/topbar/components/reading_container.dart'; +import 'package:lightmeter/screens/metering/components/topbar/topbar_shape.dart'; +import 'package:lightmeter/utils/text_line_height.dart'; + +class MeteringTopBar extends StatelessWidget { + static const _columnsCount = 3; + + final double lux; + final double ev; + final int iso; + final double nd; + + const MeteringTopBar({ + required this.lux, + required this.ev, + required this.iso, + required this.nd, + super.key, + }); + + @override + Widget build(BuildContext context) { + final columnWidth = (MediaQuery.of(context).size.width - Dimens.paddingM * (_columnsCount + 1)) / 3; + return CustomPaint( + painter: TopBarShape( + color: Theme.of(context).colorScheme.surface, + appendixSize: Size( + (MediaQuery.of(context).size.width - Dimens.paddingM * 4) / 3 + Dimens.paddingM * 2, + Dimens.paddingM + + Theme.of(context).textTheme.labelMedium!.lineHeight + + Dimens.grid4 + + Theme.of(context).textTheme.titleLarge!.lineHeight + + Dimens.paddingM * 2, + ), + ), + child: Padding( + padding: const EdgeInsets.all(Dimens.paddingM), + child: SafeArea( + bottom: false, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + IntrinsicHeight( + child: Row( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Expanded( + child: ReadingContainer( + values: [ + const ReadingValue( + label: 'Fastest', + value: 'f/5.6 - 1/2000', + ), + const ReadingValue( + label: 'Slowest', + value: 'f/45 - 1/30', + ), + ], + ), + ), + const _InnerPadding(), + SizedBox( + width: columnWidth, + child: ClipRRect( + borderRadius: BorderRadius.circular(Dimens.borderRadiusM), + child: AspectRatio( + aspectRatio: 3 / 4, + child: ColoredBox(color: Colors.black), + ), + ), + ) + ], + ), + ), + const _InnerPadding(), + Row( + children: [ + SizedBox( + width: columnWidth, + child: ReadingContainer.singleValue( + value: ReadingValue( + label: 'LUX', + value: lux.toString(), + ), + ), + ), + const _InnerPadding(), + SizedBox( + width: columnWidth, + child: ReadingContainer.singleValue( + value: ReadingValue( + label: 'EV', + value: ev.toString(), + ), + ), + ), + const _InnerPadding(), + SizedBox( + width: columnWidth, + child: ReadingContainer.singleValue( + value: ReadingValue( + label: 'ISO', + value: iso.toString(), + ), + ), + ), + ], + ), + const _InnerPadding(), + Row( + children: [ + const Spacer(), + const _InnerPadding(), + const Spacer(), + const _InnerPadding(), + SizedBox( + width: columnWidth, + child: ReadingContainer.singleValue( + value: ReadingValue( + label: 'ND', + value: nd.toString(), + ), + ), + ), + ], + ), + ], + ), + ), + ), + ); + } +} + +class _InnerPadding extends SizedBox { + const _InnerPadding() : super(height: Dimens.paddingM, width: Dimens.borderRadiusM); +} diff --git a/lib/screens/metering/metering_screen.dart b/lib/screens/metering/metering_screen.dart new file mode 100644 index 0000000..3c01f8a --- /dev/null +++ b/lib/screens/metering/metering_screen.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; +import 'package:lightmeter/screens/metering/components/topbar/components/reading_container.dart'; + +import 'components/topbar/topbar.dart'; + +class MeteringScreen extends StatelessWidget { + const MeteringScreen({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Theme.of(context).colorScheme.background, + body: Column( + children: [ + MeteringTopBar( + lux: 283, + ev: 2.3, + iso: 6400, + nd: 0, + ), + const Spacer() + ], + ), + ); + } +} diff --git a/lib/utils/text_line_height.dart b/lib/utils/text_line_height.dart new file mode 100644 index 0000000..a531074 --- /dev/null +++ b/lib/utils/text_line_height.dart @@ -0,0 +1,5 @@ +import 'package:flutter/widgets.dart'; + +extension TextLineHeight on TextStyle { + double get lineHeight => fontSize! * height!; +}