WIP Themes: climate controls and entity name

This commit is contained in:
Yegor Vialov 2020-04-04 12:00:15 +00:00
parent c40a496b6b
commit b8ba3c59e9
14 changed files with 104 additions and 93 deletions

View File

@ -18,7 +18,7 @@ class CardHeader extends StatelessWidget {
title: Text("$name",
textAlign: TextAlign.left,
overflow: TextOverflow.ellipsis,
style: new TextStyle(fontWeight: FontWeight.bold, fontSize: Sizes.largeFontSize)),
style: Theme.of(context).textTheme.headline),
);
} else {
result = new Container(width: 0.0, height: 0.0);

View File

@ -48,8 +48,7 @@ class EntityButtonCardBody extends StatelessWidget {
textOverflow: TextOverflow.ellipsis,
maxLines: 3,
wordsWrap: true,
textAlign: TextAlign.center,
fontSize: Sizes.nameFontSize,
textAlign: TextAlign.center
);
}
return Container(width: 0, height: 0);

View File

@ -126,7 +126,9 @@ class _GaugeCardBodyState extends State<GaugeCardBody> {
return Padding(
padding: EdgeInsets.only(bottom: fontSize),
child: EntityName(
fontSize: fontSize,
textStyle: Theme.of(context).textTheme.body1.copyWith(
fontSize: fontSize
),
maxLines: 1,
padding: EdgeInsets.all(0.0),
textAlign: TextAlign.center,

View File

@ -6,7 +6,6 @@ class GlanceCardEntityContainer extends StatelessWidget {
final bool showState;
final bool nameInTheBottom;
final double iconSize;
final double nameFontSize;
final bool wordsWrapInName;
GlanceCardEntityContainer({
@ -15,7 +14,6 @@ class GlanceCardEntityContainer extends StatelessWidget {
@required this.showState,
this.nameInTheBottom: false,
this.iconSize: Sizes.iconSize,
this.nameFontSize: Sizes.smallFontSize,
this.wordsWrapInName: false
}) : super(key: key);
@ -31,7 +29,7 @@ class GlanceCardEntityContainer extends StatelessWidget {
List<Widget> result = [];
if (!nameInTheBottom) {
if (showName) {
result.add(_buildName());
result.add(_buildName(context));
}
} else {
if (showState) {
@ -49,7 +47,7 @@ class GlanceCardEntityContainer extends StatelessWidget {
result.add(_buildState());
}
} else {
result.add(_buildName());
result.add(_buildName(context));
}
return Center(
@ -65,13 +63,13 @@ class GlanceCardEntityContainer extends StatelessWidget {
);
}
Widget _buildName() {
Widget _buildName(BuildContext context) {
return EntityName(
padding: EdgeInsets.only(bottom: Sizes.rowPadding),
textOverflow: TextOverflow.ellipsis,
wordsWrap: wordsWrapInName,
textAlign: TextAlign.center,
fontSize: nameFontSize,
textStyle: Theme.of(context).textTheme.caption,
);
}

View File

@ -73,7 +73,9 @@ class _LightCardBodyState extends State<LightCardBody> {
return Padding(
padding: EdgeInsets.only(bottom: fontSize),
child: EntityName(
fontSize: fontSize,
textStyle: Theme.of(context).textTheme.body1.copyWith(
fontSize: fontSize
),
maxLines: 1,
padding: EdgeInsets.all(0.0),
textAlign: TextAlign.center,

View File

@ -204,20 +204,20 @@ class _ClimateControlWidgetState extends State<ClimateControlWidget> {
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
//_buildOnOffControl(entity),
_buildTemperatureControls(entity),
_buildTargetTemperatureControls(entity),
_buildHumidityControls(entity),
_buildOperationControl(entity),
_buildFanControl(entity),
_buildSwingControl(entity),
_buildPresetModeControl(entity),
_buildAuxHeatControl(entity)
_buildTemperatureControls(entity, context),
_buildTargetTemperatureControls(entity, context),
_buildHumidityControls(entity, context),
_buildOperationControl(entity, context),
_buildFanControl(entity, context),
_buildSwingControl(entity, context),
_buildPresetModeControl(entity, context),
_buildAuxHeatControl(entity, context)
],
),
);
}
Widget _buildPresetModeControl(ClimateEntity entity) {
Widget _buildPresetModeControl(ClimateEntity entity, BuildContext context) {
if (entity.supportPresetMode) {
return ModeSelectorWidget(
options: entity.presetModes,
@ -242,7 +242,7 @@ class _ClimateControlWidgetState extends State<ClimateControlWidget> {
}
}*/
Widget _buildAuxHeatControl(ClimateEntity entity) {
Widget _buildAuxHeatControl(ClimateEntity entity, BuildContext context) {
if (entity.supportAuxHeat ) {
return ModeSwitchWidget(
caption: "Aux heat",
@ -254,7 +254,7 @@ class _ClimateControlWidgetState extends State<ClimateControlWidget> {
}
}
Widget _buildOperationControl(ClimateEntity entity) {
Widget _buildOperationControl(ClimateEntity entity, BuildContext context) {
if (entity.hvacModes != null) {
return ModeSelectorWidget(
onChange: (mode) => _setHVACMode(entity, mode),
@ -267,7 +267,7 @@ class _ClimateControlWidgetState extends State<ClimateControlWidget> {
}
}
Widget _buildFanControl(ClimateEntity entity) {
Widget _buildFanControl(ClimateEntity entity, BuildContext context) {
if (entity.supportFanMode) {
return ModeSelectorWidget(
options: entity.fanModes,
@ -280,7 +280,7 @@ class _ClimateControlWidgetState extends State<ClimateControlWidget> {
}
}
Widget _buildSwingControl(ClimateEntity entity) {
Widget _buildSwingControl(ClimateEntity entity, BuildContext context) {
if (entity.supportSwingMode) {
return ModeSelectorWidget(
onChange: (mode) => _setSwingMode(entity, mode),
@ -293,17 +293,15 @@ class _ClimateControlWidgetState extends State<ClimateControlWidget> {
}
}
Widget _buildTemperatureControls(ClimateEntity entity) {
Widget _buildTemperatureControls(ClimateEntity entity, BuildContext context) {
if ((entity.supportTargetTemperature) && (entity.temperature != null)) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("Target temperature", style: TextStyle(
fontSize: Sizes.stateFontSize
)),
Text("Target temperature", style: Theme.of(context).textTheme.body1),
TemperatureControlWidget(
value: _tmpTemperature,
fontColor: _temperaturePending ? Colors.red : Colors.black,
active: _temperaturePending,
onDec: () => _temperatureDown(entity),
onInc: () => _temperatureUp(entity),
)
@ -314,13 +312,13 @@ class _ClimateControlWidgetState extends State<ClimateControlWidget> {
}
}
Widget _buildTargetTemperatureControls(ClimateEntity entity) {
Widget _buildTargetTemperatureControls(ClimateEntity entity, BuildContext context) {
List<Widget> controls = [];
if ((entity.supportTargetTemperatureRange) && (entity.targetLow != null)) {
controls.addAll(<Widget>[
TemperatureControlWidget(
value: _tmpTargetLow,
fontColor: _temperaturePending ? Colors.red : Colors.black,
active: _temperaturePending,
onDec: () => _targetLowDown(entity),
onInc: () => _targetLowUp(entity),
),
@ -333,7 +331,7 @@ class _ClimateControlWidgetState extends State<ClimateControlWidget> {
controls.add(
TemperatureControlWidget(
value: _tmpTargetHigh,
fontColor: _temperaturePending ? Colors.red : Colors.black,
active: _temperaturePending,
onDec: () => _targetHighDown(entity),
onInc: () => _targetHighUp(entity),
)
@ -343,9 +341,7 @@ class _ClimateControlWidgetState extends State<ClimateControlWidget> {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("Target temperature range", style: TextStyle(
fontSize: Sizes.stateFontSize
)),
Text("Target temperature range", style: Theme.of(context).textTheme.body1),
Row(
children: controls,
)
@ -356,13 +352,13 @@ class _ClimateControlWidgetState extends State<ClimateControlWidget> {
}
}
Widget _buildHumidityControls(ClimateEntity entity) {
Widget _buildHumidityControls(ClimateEntity entity, BuildContext context) {
List<Widget> result = [];
if (entity.supportTargetHumidity) {
result.addAll(<Widget>[
Text(
"$_tmpTargetHumidity%",
style: TextStyle(fontSize: Sizes.largeFontSize),
style: Theme.of(context).textTheme.display1,
),
Expanded(
child: Slider(
@ -387,9 +383,7 @@ class _ClimateControlWidgetState extends State<ClimateControlWidget> {
Padding(
padding: EdgeInsets.fromLTRB(
0.0, Sizes.rowPadding, 0.0, Sizes.rowPadding),
child: Text("Target humidity", style: TextStyle(
fontSize: Sizes.stateFontSize
)),
child: Text("Target humidity", style: Theme.of(context).textTheme.body1),
),
Row(
crossAxisAlignment: CrossAxisAlignment.center,

View File

@ -33,23 +33,16 @@ class ClimateStateWidget extends StatelessWidget {
children: <Widget>[
Text("$displayState",
textAlign: TextAlign.right,
style: new TextStyle(
fontWeight: FontWeight.bold,
fontSize: Sizes.stateFontSize,
)),
style: Theme.of(context).textTheme.body2),
Text(" $targetTemp",
textAlign: TextAlign.right,
style: new TextStyle(
fontSize: Sizes.stateFontSize,
))
style: Theme.of(context).textTheme.body1)
],
),
entity.currentTemperature != null ?
Text("Currently: ${entity.currentTemperature}",
textAlign: TextAlign.right,
style: new TextStyle(
fontSize: Sizes.stateFontSize,
color: Colors.black45)
style: Theme.of(context).textTheme.subtitle
) :
Container(height: 0.0,)
],

View File

@ -5,8 +5,6 @@ class ModeSelectorWidget extends StatelessWidget {
final String caption;
final List options;
final String value;
final double captionFontSize;
final double valueFontSize;
final onChange;
final EdgeInsets padding;
@ -16,8 +14,6 @@ class ModeSelectorWidget extends StatelessWidget {
@required this.options,
this.value,
@required this.onChange,
this.captionFontSize,
this.valueFontSize,
this.padding: const EdgeInsets.fromLTRB(Sizes.leftWidgetPadding, Sizes.rowPadding, Sizes.rightWidgetPadding, 0.0),
}) : super(key: key);
@ -28,9 +24,7 @@ class ModeSelectorWidget extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("$caption", style: TextStyle(
fontSize: captionFontSize ?? Sizes.stateFontSize
)),
Text("$caption", style: Theme.of(context).textTheme.body1),
Row(
children: <Widget>[
Expanded(
@ -40,10 +34,7 @@ class ModeSelectorWidget extends StatelessWidget {
value: value,
iconSize: 30.0,
isExpanded: true,
style: TextStyle(
fontSize: valueFontSize ?? Sizes.largeFontSize,
color: Colors.black,
),
style: Theme.of(context).textTheme.title,
hint: Text("Select ${caption.toLowerCase()}"),
items: options.map((value) {
return new DropdownMenuItem<String>(

View File

@ -4,7 +4,6 @@ class ModeSwitchWidget extends StatelessWidget {
final String caption;
final onChange;
final double captionFontSize;
final bool value;
final bool expanded;
final EdgeInsets padding;
@ -13,7 +12,6 @@ class ModeSwitchWidget extends StatelessWidget {
Key key,
@required this.caption,
@required this.onChange,
this.captionFontSize,
this.value,
this.expanded: true,
this.padding: const EdgeInsets.only(left: Sizes.leftWidgetPadding, right: Sizes.rightWidgetPadding)
@ -25,7 +23,7 @@ class ModeSwitchWidget extends StatelessWidget {
padding: this.padding,
child: Row(
children: <Widget>[
_buildCaption(),
_buildCaption(context),
Switch(
onChanged: (value) => onChange(value),
value: value ?? false,
@ -35,12 +33,10 @@ class ModeSwitchWidget extends StatelessWidget {
);
}
Widget _buildCaption() {
Widget _buildCaption(BuildContext context) {
Widget captionWidget = Text(
"$caption",
style: TextStyle(
fontSize: captionFontSize ?? Sizes.stateFontSize
),
style: Theme.of(context).textTheme.body1,
);
if (expanded) {
return Expanded(

View File

@ -2,8 +2,7 @@ part of '../../../main.dart';
class TemperatureControlWidget extends StatelessWidget {
final double value;
final double fontSize;
final Color fontColor;
final bool active;
final onInc;
final onDec;
@ -12,8 +11,9 @@ class TemperatureControlWidget extends StatelessWidget {
@required this.value,
@required this.onInc,
@required this.onDec,
this.fontSize,
this.fontColor})
//this.fontSize,
this.active: false
})
: super(key: key);
@override
@ -23,10 +23,7 @@ class TemperatureControlWidget extends StatelessWidget {
children: <Widget>[
Text(
"$value",
style: TextStyle(
fontSize: fontSize ?? 24.0,
color: fontColor ?? Colors.black
),
style: active ? Theme.of(context).textTheme.display2 : Theme.of(context).textTheme.display1,
),
Column(
children: <Widget>[

View File

@ -5,18 +5,21 @@ class EntityName extends StatelessWidget {
final EdgeInsetsGeometry padding;
final TextOverflow textOverflow;
final bool wordsWrap;
final double fontSize;
final TextAlign textAlign;
final int maxLines;
final TextStyle textStyle;
const EntityName({Key key, this.maxLines, this.padding: const EdgeInsets.only(right: 10.0), this.textOverflow: TextOverflow.ellipsis, this.wordsWrap: true, this.fontSize: Sizes.nameFontSize, this.textAlign: TextAlign.left}) : super(key: key);
const EntityName({Key key, this.maxLines, this.padding: const EdgeInsets.only(right: 10.0), this.textOverflow: TextOverflow.ellipsis, this.textStyle, this.wordsWrap: true, this.textAlign: TextAlign.left}) : super(key: key);
@override
Widget build(BuildContext context) {
final EntityWrapper entityWrapper = EntityModel.of(context).entityWrapper;
TextStyle textStyle = TextStyle(fontSize: fontSize);
if (entityWrapper.entity.statelessType == StatelessEntityType.WEBLINK) {
textStyle = textStyle.apply(color: Colors.blue, decoration: TextDecoration.underline);
TextStyle tStyle;
if (textStyle == null) {
tStyle = Theme.of(context).textTheme.body1;
if (entityWrapper.entity.statelessType == StatelessEntityType.WEBLINK) {
tStyle = tStyle.apply(color: Colors.blue, decoration: TextDecoration.underline);
}
}
return Padding(
padding: padding,
@ -25,7 +28,7 @@ class EntityName extends StatelessWidget {
overflow: textOverflow,
softWrap: wordsWrap,
maxLines: maxLines,
style: textStyle,
style: tStyle,
textAlign: textAlign,
),
);

View File

@ -1,7 +1,7 @@
import 'dart:convert';
import 'dart:async';
import 'dart:math';
import 'dart:io';
//import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/material.dart';
@ -10,7 +10,7 @@ import 'package:web_socket_channel/io.dart';
import 'package:event_bus/event_bus.dart';
import 'package:flutter/widgets.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:path_provider/path_provider.dart';
//import 'package:path_provider/path_provider.dart';
import 'package:url_launcher/url_launcher.dart' as urlLauncher;
import 'package:flutter/services.dart';
import 'package:date_format/date_format.dart';
@ -35,6 +35,7 @@ import 'package:flutter_webview_plugin/flutter_webview_plugin.dart' as standalon
import 'package:webview_flutter/webview_flutter.dart';
import 'package:video_player/video_player.dart';
import 'managers/theme_manager.dart';
import 'utils/logger.dart';
part 'const.dart';
@ -226,9 +227,8 @@ class _HAClientAppState extends State<HAClientApp> {
Widget build(BuildContext context) {
return new MaterialApp(
title: appName,
theme: new ThemeData(
primarySwatch: Colors.blue,
),
theme: HAClientTheme().lightTheme,
darkTheme: HAClientTheme().darkTheme,
initialRoute: "/",
routes: {
"/": (context) => MainPage(title: 'HA Client'),

View File

@ -0,0 +1,33 @@
import 'package:flutter/material.dart';
class HAClientTheme {
static const Color defaultFontColor = Colors.black87;
static final HAClientTheme _instance = HAClientTheme
._internal();
factory HAClientTheme() {
return _instance;
}
HAClientTheme._internal();
final ThemeData lightTheme = ThemeData.light().copyWith(
textTheme: ThemeData.light().textTheme.copyWith(
display1: TextStyle(fontSize: 34, fontWeight: FontWeight.normal, color: Colors.black54),
display2: TextStyle(fontSize: 34, fontWeight: FontWeight.normal, color: Colors.redAccent),
headline: TextStyle(fontSize: 24, fontWeight: FontWeight.normal, color: defaultFontColor),
title: TextStyle(fontSize: 20, fontWeight: FontWeight.w700, color: defaultFontColor),
subhead: TextStyle(fontSize: 16, fontWeight: FontWeight.w500, color: defaultFontColor),
body1: TextStyle(fontSize: 15, fontWeight: FontWeight.normal, color: defaultFontColor),
body2: TextStyle(fontSize: 15, fontWeight: FontWeight.w500, color: defaultFontColor),
subtitle: TextStyle(fontSize: 15, fontWeight: FontWeight.w500, color: Colors.black45),
caption: TextStyle(fontSize: 13, fontWeight: FontWeight.normal, color: defaultFontColor),
overline: TextStyle(fontSize: 10, fontWeight: FontWeight.normal, color: Colors.black54),
)
);
final ThemeData darkTheme = ThemeData.dark();
}

View File

@ -115,7 +115,7 @@ class _IntegrationSettingsPageState extends State<IntegrationSettingsPage> {
scrollDirection: Axis.vertical,
padding: const EdgeInsets.all(20.0),
children: <Widget>[
Text("Location tracking", style: TextStyle(fontSize: Sizes.largeFontSize-2)),
Text("Location tracking", style: Theme.of(context).textTheme.title),
Container(height: Sizes.rowPadding,),
InkWell(
onTap: () => Launcher.launchURLInCustomTab(context: context, url: "http://ha-client.app/docs#location-tracking"),
@ -153,21 +153,24 @@ class _IntegrationSettingsPageState extends State<IntegrationSettingsPage> {
//Expanded(child: Container(),),
FlatButton(
padding: EdgeInsets.all(0.0),
child: Text("-", style: TextStyle(fontSize: Sizes.largeFontSize)),
child: Text("-", style: Theme.of(context).textTheme.title),
onPressed: () => decLocationInterval(),
),
Text("$_locationInterval", style: TextStyle(fontSize: Sizes.largeFontSize)),
Text("$_locationInterval", style: Theme.of(context).textTheme.title),
FlatButton(
padding: EdgeInsets.all(0.0),
child: Text("+", style: TextStyle(fontSize: Sizes.largeFontSize)),
child: Text("+", style: Theme.of(context).textTheme.title),
onPressed: () => incLocationInterval(),
),
],
),
Divider(),
Text("Integration status", style: TextStyle(fontSize: Sizes.largeFontSize-2)),
Text("Integration status", style: Theme.of(context).textTheme.title),
Container(height: Sizes.rowPadding,),
Text("${HomeAssistant().userName}'s ${DeviceInfoManager().model}, ${DeviceInfoManager().osName} ${DeviceInfoManager().osVersion}"),
Text(
"${HomeAssistant().userName}'s ${DeviceInfoManager().model}, ${DeviceInfoManager().osName} ${DeviceInfoManager().osVersion}",
style: Theme.of(context).textTheme.subtitle,
),
Container(height: 6.0,),
Text("Here you can manually check if HA Client integration with your Home Assistant works fine. As mobileApp integration in Home Assistant is still in development, this is not 100% correct check."),
//Divider(),