Automation wip + others + notifications wip !

This commit is contained in:
Fransolet Thomas 2023-07-31 07:52:55 +02:00
parent 87e8c47003
commit 8a269dc8d4
47 changed files with 1798 additions and 100 deletions

View File

@ -21,6 +21,8 @@ flutter clean
flutter pub get flutter pub get
flutter packages pub get
flutter pub run build_runner build --delete-conflicting-outputs flutter pub run build_runner build --delete-conflicting-outputs
Le fichier est dans le projet. Le fichier est dans le projet.

View File

@ -24,9 +24,10 @@ if (flutterVersionName == null) {
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
apply plugin: 'com.google.gms.google-services'
android { android {
compileSdkVersion 32 compileSdkVersion 33
sourceSets { sourceSets {
main.java.srcDirs += 'src/main/kotlin' main.java.srcDirs += 'src/main/kotlin'
@ -110,4 +111,14 @@ flutter {
dependencies { dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
// Import the Firebase BoM
implementation platform('com.google.firebase:firebase-bom:32.2.0')
// TODO: Add the dependencies for Firebase products you want to use
// When using the BoM, don't specify versions in Firebase dependencies
implementation 'com.google.firebase:firebase-analytics'
implementation 'com.google.firebase:firebase-messaging'
// Add the dependencies for any other desired Firebase products
// https://firebase.google.com/docs/android/setup#available-libraries
} }

View File

@ -0,0 +1,39 @@
{
"project_info": {
"project_number": "246480640287",
"project_id": "unov---myhomie",
"storage_bucket": "unov---myhomie.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:246480640287:android:55411924cff9636eb9382a",
"android_client_info": {
"package_name": "be.unov.myhomie"
}
},
"oauth_client": [
{
"client_id": "246480640287-iu9np24gr3oaab8gs0c5o8n5at1e3it1.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyD_3Acf-JR2Uw4lCmCR_oKh6U-AKcuYj4o"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "246480640287-iu9np24gr3oaab8gs0c5o8n5at1e3it1.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
}
],
"configuration_version": "1"
}

View File

@ -1,5 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="be.myhomie.myhomie_app"> package="be.unov.myhomie">
<!-- Flutter needs it to communicate with the running application <!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc. to allow setting breakpoints, to provide hot reload, etc.
--> -->

View File

@ -1,9 +1,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="be.myhomie.myhomie_app"> package="be.unov.myhomie">
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<application <application
android:label="MyHomie" android:label="MyHomie"
android:usesCleartextTraffic="true" android:usesCleartextTraffic="true"
android:icon="@mipmap/ic_launcher"> android:icon="@mipmap/ic_launcher">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
@ -20,6 +20,9 @@
android:name="io.flutter.embedding.android.NormalTheme" android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme" android:resource="@style/NormalTheme"
/> />
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="@string/default_notification_channel_id" />
<!-- Displays an Android View that continues showing the launch screen <!-- Displays an Android View that continues showing the launch screen
Drawable until Flutter paints its first frame, then this splash Drawable until Flutter paints its first frame, then this splash
screen fades out. A splash screen is useful to avoid any visual screen fades out. A splash screen is useful to avoid any visual
@ -33,11 +36,23 @@
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter> </intent-filter>
<intent-filter>
<action android:name="FLUTTER_NOTIFICATION_CLICK" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity> </activity>
<!-- Don't delete the meta-data below. <!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java --> This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data <meta-data
android:name="flutterEmbedding" android:name="flutterEmbedding"
android:value="2" /> android:value="2" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/logo" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="@color/colorPrimary" />
</application> </application>
</manifest> </manifest>

View File

@ -1,4 +1,4 @@
package be.myhomie.myhomie_app package be.unov.myhomie
import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.android.FlutterActivity

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#6025b6</color>
</resources>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">MyHomie</string>
<!-- Replace "000000000000" with your Facebook App ID here. -->
<!-- <string name="facebook_app_id">742185533300745</string> -->
<!--
Replace "000000000000" with your Facebook App ID here.
**NOTE**: The scheme needs to start with `fb` and then your ID.
-->
<!--<string name="fb_login_protocol_scheme">fb742185533300745</string>-->
<string name="default_notification_channel_id">main</string>
</resources>

View File

@ -1,5 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="be.myhomie.myhomie_app"> package="be.unov.myhomie">
<!-- Flutter needs it to communicate with the running application <!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc. to allow setting breakpoints, to provide hot reload, etc.
--> -->

View File

@ -1,5 +1,5 @@
#Fri Mar 17 18:48:37 CET 2023 #Fri Jul 28 17:03:08 CEST 2023
VERSION_BUILD=19 VERSION_BUILD=32
VERSION_MAJOR=1 VERSION_MAJOR=1
VERSION_MINOR=0 VERSION_MINOR=0
VERSION_PATCH=0 VERSION_PATCH=0

View File

@ -8,6 +8,7 @@ buildscript {
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:4.1.0' classpath 'com.android.tools.build:gradle:4.1.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.google.gms:google-services:4.3.15'
} }
} }

View File

@ -0,0 +1,21 @@
import 'package:flutter/material.dart';
import 'package:mycore_api/api.dart';
IconData getAlarmModeIcon(AlarmModeDTO alarmModeDTO) {
switch(alarmModeDTO.type) {
case AlarmType.desarmed:
return Icons.lock_open;
case AlarmType.absent:
return Icons.person_off;
case AlarmType.home:
return Icons.home_outlined;
case AlarmType.geolocalized:
return Icons.location_on;
case AlarmType.programmed:
return Icons.schedule;
case AlarmType.custom:
return Icons.tune;
default:
return Icons.device_unknown;
}
}

View File

@ -0,0 +1,77 @@
import 'package:flutter/material.dart';
import 'package:myhomie_app/Models/homieContext.dart';
import 'package:myhomie_app/app_context.dart';
import 'package:provider/provider.dart';
class CustomAppBar extends StatefulWidget implements PreferredSizeWidget {
CustomAppBar({Key? key, required this.title, this.titleIcon, this.isTextSizeButton});
final String title;
final IconData? titleIcon;
bool? isTextSizeButton = false;
final double _preferredHeight = 50;
@override
State<CustomAppBar> createState() => _CustomAppBarState();
@override
Size get preferredSize => Size.fromHeight(_preferredHeight);
}
class _CustomAppBarState extends State<CustomAppBar> {
@override
Widget build(BuildContext context) {
final appContext = Provider.of<AppContext>(context);
HomieAppContext homieAppContext = appContext.getContext();
final notchInset = MediaQuery.of(context).padding;
return AppBar(
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(widget.title),
Padding(
padding: const EdgeInsets.all(8.0),
child: widget.titleIcon != null ? Icon(widget.titleIcon) : null,
),
],
),
centerTitle: true,
/*leading: widget.isHomeButton ? IconButton(
icon: const Icon(Icons.home),
onPressed: () {
// Set new State
setState(() {
visitAppContext.configuration = null;
visitAppContext.isScanningBeacons = false;
//Navigator.of(context).pop();
Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(
builder: (context) => const HomePage(),
),(route) => false);
});
}
) : null,*/
actions: [
],
flexibleSpace: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.centerRight,
end: Alignment.centerLeft,
colors: [
/*Color(0xFFDD79C2),
Color(0xFFB65FBE),
Color(0xFF9146BA),
Color(0xFF7633B8),
Color(0xFF6528B6),
Color(0xFF6025B6)*/
Color(0xFF306bac),
Color(0xFF308aae),
Color(0xFF309cb0),
],
),
),
),
);
}
}

View File

@ -67,8 +67,8 @@ class _CustomBottomNavigationBarState extends State<CustomBottomNavigationBar> {
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [ children: [
CustomNavItem(setPage: setPage, icon: NavItemIcon.energy, id: 3), CustomNavItem(setPage: setPage, icon: NavItemIcon.devices, id: 3),
CustomNavItem(setPage: setPage, icon: NavItemIcon.profile, id: 4), CustomNavItem(setPage: setPage, icon: NavItemIcon.energy, id: 4),
], ],
), ),
), ),

View File

@ -54,22 +54,28 @@ class CustomNavItem extends StatelessWidget {
size: 25, size: 25,
color: Colors.white, color: Colors.white,
); );
case 'energy': case 'devices':
return Icon( return Icon(
Icons.power, Icons.devices_other,
size: 25, size: 25,
color: Colors.white, color: Colors.white,
); );
case 'profile': //Todo show user image ? case 'energy':
return Icon(
Icons.bolt,
size: 25,
color: Colors.white,
);
/*case 'profile': //Todo show user image ?
return Icon( return Icon(
Icons.person, Icons.person,
size: 25, size: 25,
color: Colors.white, color: Colors.white,
); );*/
} }
//return new FlareActor("assets/animations/bottom_navigation/"+ icon.toString().split(".").last +".flr", alignment:Alignment.center, fit:BoxFit.contain, animation: index == icon.index ? "Selected" : "Unselected"); //icon.index //return new FlareActor("assets/animations/bottom_navigation/"+ icon.toString().split(".").last +".flr", alignment:Alignment.center, fit:BoxFit.contain, animation: index == icon.index ? "Selected" : "Unselected"); //icon.index
} }
} }
enum NavItemIcon { home, security, automations, energy, profile } enum NavItemIcon { home, security, automations, devices, energy, profile }

View File

@ -0,0 +1,86 @@
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/material.dart';
import '../constants.dart';
class CheckInputContainer extends StatefulWidget {
final bool isChecked;
final IconData? icon;
final String label;
final ValueChanged<bool> onChanged;
final double fontSize;
const CheckInputContainer({
Key? key,
required this.isChecked,
this.icon,
required this.label,
required this.onChanged,
this.fontSize = 20
}) : super(key: key);
@override
_CheckInputContainerState createState() => _CheckInputContainerState();
}
class _CheckInputContainerState extends State<CheckInputContainer> {
bool? isChecked;
@override
void initState() {
setState(() {
isChecked = widget.isChecked;
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
children: [
if(widget.icon != null)
Padding(
padding: const EdgeInsets.only(right: 8.0),
child: Icon(
widget.icon,
color: kMainColor,
size: 25.0,
),
),
if(widget.label != null)
AutoSizeText(
widget.label,
style: new TextStyle(fontSize: widget.fontSize, fontWeight: FontWeight.w300),
maxLines: 2,
maxFontSize: widget.fontSize,
textAlign: TextAlign.center,
),
],
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Container(
width: 50,
height: 50,
child: Checkbox(
shape: CircleBorder(),
value: isChecked,
checkColor: Colors.white,
activeColor: kMainColor,
onChanged: (bool? value) {
setState(() {
isChecked = value;
});
widget.onChanged(value!);
},
),
),
),
],
),
);
}
}

View File

@ -0,0 +1,138 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:myhomie_app/Components/Buttons/rounded_button.dart';
import 'package:myhomie_app/constants.dart';
class Consts {
Consts._();
static const double padding = 16.0;
static const double avatarRadius = 70.0;
}
class CustomDialog extends StatelessWidget {
String title, description, buttonText;
String? iconSvg;
Function onPress;
CustomDialog({
required this.title,
required this.description,
required this.buttonText,
this.iconSvg,
required this.onPress
});
@override
Widget build(BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(Consts.padding),
),
elevation: 0.0,
backgroundColor: Colors.transparent,
child: dialogContent(context),
);
}
dialogContent(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Stack(
children: <Widget>[
Container(
padding: EdgeInsets.only(
top: Consts.avatarRadius + Consts.padding,
bottom: Consts.padding,
left: Consts.padding,
right: Consts.padding,
),
margin: EdgeInsets.only(top: Consts.avatarRadius),
decoration: new BoxDecoration(
color: Colors.white,
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(Consts.padding),
boxShadow: [
BoxShadow(
color: Colors.black26,
blurRadius: 10.0,
offset: const Offset(0.0, 10.0),
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min, // To make the card compact
children: <Widget>[
SizedBox(height: 16.0),
Text(
description,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16.0,
),
),
SizedBox(height: 22.0),
Align(
alignment: Alignment.bottomRight,
child: RoundedButton(
press: () {
onPress();
Navigator.of(context).pop(); // To close the dialog
},
text: buttonText,
),
),
],
),
),
Positioned(
left: Consts.padding,
right: Consts.padding,
child: Container(
width: size.width *0.18,
height: size.height *0.18,
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: [
Color(0xFFDD79C2),
Color(0xFFB65FBE),
Color(0xFF9146BA),
Color(0xFF7633B8),
Color(0xFF6528B6),
Color(0xFF6025B6)
],
),
//borderRadius: BorderRadius.circular(10.0),
),
child: Center(
child: Stack(
children: [
if (iconSvg != null)
SvgPicture.asset(
iconSvg!,
height: 65,
color: Colors.white,
)
else
Container(
width: size.width*0.3,
height: size.width*0.23,
child: Center(
child: Text(
title,
style: kHeadingTextStyle,
textAlign: TextAlign.center,
overflow: TextOverflow.clip
),
),
)
]))
),
),
],
);
}
}

View File

@ -9,6 +9,7 @@ class RoundedInputField extends StatelessWidget {
final String? initialValue; final String? initialValue;
final Color color, textColor, iconColor; final Color color, textColor, iconColor;
final int? maxLength; final int? maxLength;
final double? fontSize;
const RoundedInputField({ const RoundedInputField({
Key? key, Key? key,
this.hintText, this.hintText,
@ -19,6 +20,7 @@ class RoundedInputField extends StatelessWidget {
this.iconColor = kTitleTextColor, // TODO this.iconColor = kTitleTextColor, // TODO
this.onChanged, this.onChanged,
this.maxLength, // 50 this.maxLength, // 50
this.fontSize = 20,
}) : super(key: key); }) : super(key: key);
@override @override
@ -30,7 +32,7 @@ class RoundedInputField extends StatelessWidget {
initialValue: initialValue, initialValue: initialValue,
cursorColor: textColor, cursorColor: textColor,
maxLength: maxLength, maxLength: maxLength,
style: TextStyle(fontSize: 20, color: textColor), style: TextStyle(fontSize: fontSize, color: textColor),
decoration: InputDecoration( decoration: InputDecoration(
icon: icon != null ? Icon( icon: icon != null ? Icon(
icon, icon,

View File

@ -0,0 +1,65 @@
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/material.dart';
import 'package:myhomie_app/Components/rounded_input_field.dart';
import 'package:myhomie_app/constants.dart';
class StringInputContainer extends StatelessWidget {
final Color color;
final Color textColor;
final String label;
final String? initialValue;
final ValueChanged<String>? onChanged;
final bool isUrl;
final bool isSmall;
final int maxLength;
final double fontSize;
final double fontSizeText;
const StringInputContainer({
Key? key,
this.color = kMainColor,
this.textColor = Colors.black,
required this.label,
this.initialValue,
this.onChanged,
this.isUrl = false,
this.isSmall = false,
this.maxLength = 50,
this.fontSize = 25,
this.fontSizeText = 20,
}) : super(key: key);
@override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Container(
child: Row(
children: [
Align(
alignment: AlignmentDirectional.centerStart,
child: AutoSizeText(
label,
style: TextStyle(fontSize: fontSize, fontWeight: FontWeight.w300),
maxLines: 2,
maxFontSize: fontSize,
textAlign: TextAlign.center,
),
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Container(
width: isUrl ? size.width *0.6 : isSmall ? size.width *0.1 : size.width *0.65,
child: RoundedInputField(
color: color,
textColor: textColor,
fontSize: fontSizeText,
initialValue: initialValue,
onChanged: onChanged,
maxLength: maxLength,
),
),
),
],
),
);
}
}

View File

@ -0,0 +1,46 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:myhomie_app/Components/custom_dialog.dart';
import 'package:myhomie_app/Helpers/PushNotificationService.dart';
class NotificationManager {
static BuildContext? _context;
static String defaultButtonLabel = "Merci !";
static init({required BuildContext context}) {
_context = context;
}
static handleDataMsg(Map<String, dynamic> data){
}
static handleNotificationMsg(PushNotificationMessage message) {
//We can add showDialog key in future
/*if (data.containsKey('showDialog')) {
// Handle data message with dialog
_showDialog(data);
}*/
_showDialog(message: message);
}
static _showDialog({required PushNotificationMessage message}) {
var buttonLabel = message.data.labelButton == null ? defaultButtonLabel : message.data.labelButton;
showDialog(
context: _context!,
builder: (BuildContext context) => CustomDialog(
title: message.title,
description: message.body,
buttonText: buttonLabel!,
onPress: () => {
/*if (message.data.type != null) {
PageSwitcher(message.data.type)
}*/
}
),
);
}
}

View File

@ -0,0 +1,168 @@
import 'dart:io';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:myhomie_app/Helpers/NotificationManager.dart';
import 'package:myhomie_app/Models/homieContext.dart';
import '../constants.dart';
class PushNotificationService {
//final FirebaseMessaging _fcm;
PushNotificationService(); //this._fcm
goToPage(Map<String, dynamic> message) {
var notification = PushNotificationMessage(
title: message['notification']['title'],
body: message['notification']['body'],
data: DataNotification(
collapseKey: message['data']['title'],
type: message['data']['type'])
);
//PageSwitcher(notification.data.type);
Fluttertoast.showToast(
msg: 'onResume or onLaunch '+ notification.title + ' : ' + notification.body,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
timeInSecForIosWeb: 1,
backgroundColor: kMainColor,
textColor: Colors.white,
fontSize: 16.0
);
}
Future initialise(HomieAppContext? homieAppContext, {required BuildContext context}) async {
if (Platform.isIOS) {
//_fcm.requestPermission(); // IosNotificationSettings
FirebaseMessaging.instance.requestPermission();
}
//_fcm.subscribeToTopic("main");
FirebaseMessaging.instance.subscribeToTopic("main");
if(homieAppContext != null) {
if (homieAppContext.userId != null) {
print('MyHomie USER ID for fcm notification = ' + homieAppContext.userId.toString());
FirebaseMessaging.instance.subscribeToTopic(homieAppContext.userId!);
}
}
// If you want to test the push notification locally,
// you need to get the token and input to the Firebase console
// https://console.firebase.google.com/project/YOUR_PROJECT_ID/notification/compose
String? token = await FirebaseMessaging.instance.getToken();
print("FirebaseMessaging token: $token");
FirebaseMessaging.instance.getInitialMessage().then(
(value) {
debugPrint("COUCOUCOUC $value");
},
);
FirebaseMessaging.onMessage.listen((data) {
var notification;
print("onMessage: $data");
print(data);
if (Platform.isAndroid) {
notification = PushNotificationMessage(
title: data.notification!.title!,
body: data.notification!.body!,
data: DataNotification(
//labelButton: message['data']['labelButton'],
type: data.messageType!)
);
}
/*if (Platform.isIOS) {
notification = PushNotificationMessage(
title: message['aps']['alert']['title'],
body: message['aps']['alert']['body'],
data: DataNotification(
labelButton: message['labelButton'],
type: message['type'])
);
}*/
NotificationManager.handleNotificationMsg(notification);
// show notification UI here
});
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
print('A new onMessageOpenedApp event was published!');
/*Navigator.pushNamed(
context,
'/message',
arguments: MessageArguments(message, true),
);*/
});
/*_fcm.configure(
onMessage: (Map<String, dynamic> message) async {
},
onLaunch: (Map<String, dynamic> message) async {
print("onLaunch: $message");
this.goToPage(message);
},
onResume: (Map<String, dynamic> message) async {
print("onResume: $message");
this.goToPage(message);
},
);*/
}
}
class PushNotificationMessage {
final String title;
final String body;
final DataNotification data;
PushNotificationMessage({
required this.title,
required this.body,
required this.data
});
}
class DataNotification {
final String? collapseKey;
final String type;
final String? labelButton;
DataNotification({
this.collapseKey,
required this.type,
this.labelButton
});
}
/*PageSwitcher(String type) {
switch(type) {
case "home":
pageController.jumpToPage(NavItemIcon.home.index);
break;
case "advices":
// In case of new advice, need to reload advices list automatically
pageController.jumpToPage(NavItemIcon.advices.index);
break;
case "scan":
pageController.jumpToPage(NavItemIcon.scan.index);
break;
case "shop":
pageController.jumpToPage(NavItemIcon.wallet.index);
break;
case "profile":
pageController.jumpToPage(NavItemIcon.profile.index);
break;
default:
pageController.jumpToPage(NavItemIcon.home.index);
break;
}
}*/

View File

@ -0,0 +1,213 @@
import 'dart:convert';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:mycore_api/api.dart';
import 'package:mycore_api/api.dart' as API;
import 'package:myhomie_app/Components/Alarms/getCurrentAlarmModeIcon.dart';
import 'package:myhomie_app/Components/Custom_Navigation_Bar/CustomAppBar.dart';
import 'package:myhomie_app/Components/check_input_container.dart';
import 'package:myhomie_app/Components/loading_common.dart';
import 'package:myhomie_app/Components/string_input_container.dart';
import 'package:myhomie_app/Models/homieContext.dart';
import 'package:myhomie_app/app_context.dart';
import 'package:myhomie_app/constants.dart';
import 'package:provider/provider.dart';
class AutomationDetailPage extends StatefulWidget {
const AutomationDetailPage({Key? key, required this.automationDTO}) : super(key: key);
final API.AutomationDTO automationDTO;
@override
State<AutomationDetailPage> createState() => _AutomationDetailPageState();
}
class _AutomationDetailPageState extends State<AutomationDetailPage> {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
AutomationDetailDTO? automationDetailDTO;
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
final appContext = Provider.of<AppContext>(context);
Size size = MediaQuery.of(context).size;
//final notchInset = MediaQuery.of(context).padding;
HomieAppContext homieAppContext = appContext.getContext();
debugPrint(widget.automationDTO.id!);
return Scaffold(
key: _scaffoldKey,
appBar: CustomAppBar(
title: widget.automationDTO.name!,
//titleIcon: getAlarmModeIcon(widget.alarmMode),
isTextSizeButton: true,
),
body: FutureBuilder(
future: homieAppContext.clientAPI.automationApi!.automationGetDetail(widget.automationDTO.id!),
builder: (context, AsyncSnapshot<AutomationDetailDTO?> snapshot) {
if(snapshot.data != null ) {
automationDetailDTO = snapshot.data;
return SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
width: size.width *1.1,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: StringInputContainer(
label: "Nom:",
color: kMainColor,
textColor: Colors.white,
initialValue: automationDetailDTO!.name,
onChanged: (String value) {
setState(() {
automationDetailDTO!.name = value;
// TODO SAVE or not
});
},
),
),
),
/*Padding(
padding: const EdgeInsets.all(8.0),
child: CheckInputContainer(
icon: Icons.notifications_active,
label: "Notification :",
fontSize: 20,
isChecked: alarmModeDetailDTO!.notification!,
onChanged: (bool value) {
alarmModeDetailDTO!.notification = value;
},
),
),*/
ExpansionTile(
title: Text(
"Triggers",
style: TextStyle(
fontSize: 18.0,
fontWeight: FontWeight.bold
),
),
children: [
for(var trigger in automationDetailDTO!.triggers!)
if(automationDetailDTO!.devices!.where((d) => d.id == trigger.deviceId).isNotEmpty)
ExpansionTile(
title: Text(automationDetailDTO!.devices!.firstWhere((d) => d.id == trigger.deviceId).name!),
children: <Widget>[
ListTile(
title: Text("name: "+trigger.stateName! + " - " + "value: "+ trigger.stateValue!),
)
],
),
ListTile(
title: Text("Ajouter +", style: TextStyle(), textAlign: TextAlign.center),
tileColor: Colors.lightGreen,
onTap: () {
// Show popup ajout
debugPrint("Add device to trigger popup");
},
)
],
),
ExpansionTile(
title: Text(
"Actions",
style: TextStyle(
fontSize: 18.0,
fontWeight: FontWeight.bold
),
),
children: [
for(var action in automationDetailDTO!.actions!)
actionTile(action),
ListTile(
title: Text("Ajouter +", style: TextStyle(), textAlign: TextAlign.center),
tileColor: Colors.lightGreen,
onTap: () {
// Show popup ajout
debugPrint("Add device to trigger popup");
},
)
],
),
Text("Actions"),
for(var device in automationDetailDTO!.devices!.where((d) => automationDetailDTO!.actions!.map((t)=> t.deviceId).contains(d.id)))
Text(device.name!),
Text(automationDetailDTO!.actions!.toString()),
Text("Devices"),
Text(automationDetailDTO!.devices!.toString()),
],
),
);
} else {
return const LoadingCommon();
}
}
)
);
}
actionTile(API.Action action) {
switch(action.type) {
case ActionType.DELAY:
return ListTile(
title: Text(action.type.toString()),
);
case ActionType.DEVICE:
return ExpansionTile(
title: Text(action.type.toString()),
children: [
if(automationDetailDTO!.devices!.where((d) => d.id == action.deviceId).isNotEmpty)
ExpansionTile(
title: Text(automationDetailDTO!.devices!.firstWhere((d) => d.id == action.deviceId).name!),
children: [
ListTile(
title: Text(action.states.toString())
),
],
)
],
);
case ActionType.GROUP:
return ListTile(
title: Text(action.type.toString()),
);
case ActionType.HTTP:
return ListTile(
title: Text(action.type.toString()),
);
case ActionType.MQTT:
return ExpansionTile(
title: Text(action.type.toString()),
children: [
ListTile(
title: Text(action.rawRequest!),
)
],
);
case ActionType.zIGBEE2MQTT:
return ListTile(
title: Text(action.type.toString()),
);
}
}
}

View File

@ -1,5 +1,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mycore_api/api.dart';
import 'package:myhomie_app/Components/loading_common.dart';
import 'package:myhomie_app/Models/homieContext.dart';
import 'package:myhomie_app/Screens/Main/Automations/automationDetailPage.dart';
import 'package:myhomie_app/app_context.dart'; import 'package:myhomie_app/app_context.dart';
import 'package:myhomie_app/constants.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class AutomationsScreen extends StatefulWidget { class AutomationsScreen extends StatefulWidget {
@ -11,7 +16,7 @@ class AutomationsScreen extends StatefulWidget {
class _AutomationsScreenState extends State<AutomationsScreen> { class _AutomationsScreenState extends State<AutomationsScreen> {
bool isLoading = true; bool isLoading = true;
//List<Message> messages; List<AutomationDTO>? allAutomations;
@override @override
void initState() { void initState() {
@ -22,47 +27,103 @@ class _AutomationsScreenState extends State<AutomationsScreen> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size; Size size = MediaQuery.of(context).size;
final appContext = Provider.of<AppContext>(context); final appContext = Provider.of<AppContext>(context);
HomieAppContext homieAppContext = appContext.getContext();
return interfaceElements(); return SingleChildScrollView(
/*if(appContext.getContext().feed != null) {
return interfaceElements();
} else {
return FutureBuilder(
future: Message.getMessages(this.messages, appContext, false, true),
builder: (context, AsyncSnapshot<List<Message>> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return interfaceElements();
} else if (snapshot.connectionState == ConnectionState.none) {
print('ConnectionState.none');
return Text("No data");
} else {
return Container(height: size.height * 0.2, child: Loading());
}
}
);
}*/
}
interfaceElements() {
Size size = MediaQuery.of(context).size;
final appContext = Provider.of<AppContext>(context);
return RefreshIndicator(
color: Theme.of(context).primaryColor,
displacement: 20,
onRefresh: () async {
print("TODO refresh");
//await Message.getMessages(this.messages, appContext, true, true);
},
child: Container( child: Container(
height: size.height * 0.8, height: size.height * 0.9,
child: SingleChildScrollView( child: FutureBuilder(
child: Column( future: homieAppContext.clientAPI.automationApi!.automationGetAll(homieAppContext.homeId!),
mainAxisAlignment: MainAxisAlignment.start, builder: (context, AsyncSnapshot<List<AutomationDTO>?> snapshot) {
children: [ if (snapshot.connectionState == ConnectionState.done) {
Text("TODO Automations") allAutomations = snapshot.data;
], return Padding(
), padding: const EdgeInsets.all(8.0),
child: RefreshIndicator(
color: Theme.of(context).primaryColor,
displacement: 20,
onRefresh: () async {
print("TODO refresh");
setState(() {});
return Future(() => null);
//await Message.getMessages(this.messages, appContext, true, true);
},
child: ListView.builder(
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: InkWell(
onTap: () {
debugPrint(allAutomations![index].toString());
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AutomationDetailPage(
automationDTO: allAutomations![index],
),
),
);
},
child: Container(
height: size.height * 0.1,
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(20.0),
border: Border.all(
color: kBackgroundSecondGrey.withOpacity(0.35),
width: 0.2,
),
boxShadow: [
BoxShadow(
color: kMainColor.withOpacity(0.35),
//spreadRadius: 0.15,
blurRadius: 5,
offset: const Offset(0, 10), // changes position of shadow
),
],
),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text(allAutomations![index].name!),
Switch(
// thumb color (round icon)
activeColor: kMainColor,
activeTrackColor: Colors.grey.shade400,
inactiveThumbColor: Colors.blueGrey.shade600,
inactiveTrackColor: Colors.grey.shade400,
splashRadius: 50.0,
// boolean variable value
value: allAutomations![index].active!,
// changes the state of the switch
onChanged: (bool value) {
/*setState(() {
allAutomations![index].active = value;
// TODO save
});*/
}
),
],
),
),
),
);
},
itemCount: allAutomations!.length
),
),
);
} else if (snapshot.connectionState == ConnectionState.none) {
print('ConnectionState.none');
return Text("No data");
} else {
return Container(height: size.height * 0.2, child: LoadingCommon());
}
}
), ),
), ),
); );

View File

@ -0,0 +1,70 @@
import 'package:flutter/material.dart';
import 'package:myhomie_app/app_context.dart';
import 'package:provider/provider.dart';
class DevicesScreen extends StatefulWidget {
DevicesScreen({Key? key}) : super(key: key);
@override
_DevicesScreenState createState() => _DevicesScreenState();
}
class _DevicesScreenState extends State<DevicesScreen> {
bool isLoading = true;
//List<Message> messages;
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
final appContext = Provider.of<AppContext>(context);
return interfaceElements();
/*if(appContext.getContext().feed != null) {
return interfaceElements();
} else {
return FutureBuilder(
future: Message.getMessages(this.messages, appContext, false, true),
builder: (context, AsyncSnapshot<List<Message>> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return interfaceElements();
} else if (snapshot.connectionState == ConnectionState.none) {
print('ConnectionState.none');
return Text("No data");
} else {
return Container(height: size.height * 0.2, child: Loading());
}
}
);
}*/
}
interfaceElements() {
Size size = MediaQuery.of(context).size;
final appContext = Provider.of<AppContext>(context);
return RefreshIndicator(
color: Theme.of(context).primaryColor,
displacement: 20,
onRefresh: () async {
print("TODO refresh");
//await Message.getMessages(this.messages, appContext, true, true);
},
child: Container(
height: size.height * 0.8,
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text("TODO Devices")
],
),
),
),
);
}
}

View File

@ -3,6 +3,7 @@ import 'package:mycore_api/api.dart';
import 'package:myhomie_app/Components/loading.dart'; import 'package:myhomie_app/Components/loading.dart';
import 'package:myhomie_app/Components/loading_common.dart'; import 'package:myhomie_app/Components/loading_common.dart';
import 'package:myhomie_app/Models/homieContext.dart'; import 'package:myhomie_app/Models/homieContext.dart';
import 'package:myhomie_app/Screens/Main/Home/roomDetailPage.dart';
import 'package:myhomie_app/app_context.dart'; import 'package:myhomie_app/app_context.dart';
import 'package:myhomie_app/constants.dart'; import 'package:myhomie_app/constants.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -86,10 +87,19 @@ class _HomeScreenState extends State<HomeScreen> {
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
return InkWell( return InkWell(
onTap: () { onTap: () {
setState(() { debugPrint(roomsMaindetails[index].toString());
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => RoomDetailPage(
roomMainDetailDTO: roomsMaindetails[index]
)
),
);
/*setState(() {
//selectedSection = menuDTO.sections[index]; //selectedSection = menuDTO.sections[index];
print("Hero to room detail"); print("Hero to room detail");
}); });*/
}, },
child: Container( child: Container(
decoration: boxDecorationRoom(roomsMaindetails[index], false), decoration: boxDecorationRoom(roomsMaindetails[index], false),

View File

@ -0,0 +1,139 @@
import 'dart:convert';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:mycore_api/api.dart';
import 'package:mycore_api/api.dart' as API;
import 'package:myhomie_app/Components/Alarms/getCurrentAlarmModeIcon.dart';
import 'package:myhomie_app/Components/Custom_Navigation_Bar/CustomAppBar.dart';
import 'package:myhomie_app/Components/check_input_container.dart';
import 'package:myhomie_app/Components/loading_common.dart';
import 'package:myhomie_app/Components/string_input_container.dart';
import 'package:myhomie_app/Models/homieContext.dart';
import 'package:myhomie_app/app_context.dart';
import 'package:myhomie_app/constants.dart';
import 'package:provider/provider.dart';
class RoomDetailPage extends StatefulWidget {
const RoomDetailPage({Key? key, required this.roomMainDetailDTO}) : super(key: key);
final API.RoomMainDetailDTO roomMainDetailDTO;
@override
State<RoomDetailPage> createState() => _RoomDetailPagePageState();
}
class _RoomDetailPagePageState extends State<RoomDetailPage> {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
API.RoomDetailDTO? roomDetailDTO;
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
final appContext = Provider.of<AppContext>(context);
Size size = MediaQuery.of(context).size;
//final notchInset = MediaQuery.of(context).padding;
HomieAppContext homieAppContext = appContext.getContext();
debugPrint(widget.roomMainDetailDTO.id!);
return Scaffold(
key: _scaffoldKey,
appBar: CustomAppBar(
title: widget.roomMainDetailDTO.name!,
//titleIcon: getAlarmModeIcon(widget.alarmMode),
isTextSizeButton: true,
),
body: FutureBuilder(
future: homieAppContext.clientAPI.roomApi!.roomGetDetail(widget.roomMainDetailDTO.id!),
builder: (context, AsyncSnapshot<API.RoomDetailDTO?> snapshot) {
if(snapshot.data != null ) {
roomDetailDTO = snapshot.data;
return SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
width: size.width *1.1,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: StringInputContainer(
label: "Nom:",
color: kMainColor,
textColor: Colors.white,
initialValue: roomDetailDTO!.name,
onChanged: (String value) {
setState(() {
roomDetailDTO!.name = value;
// TODO SAVE or not
});
},
),
),
),
/*Padding(
padding: const EdgeInsets.all(8.0),
child: CheckInputContainer(
icon: Icons.notifications_active,
label: "Notification :",
fontSize: 20,
isChecked: alarmModeDetailDTO!.notification!,
onChanged: (bool value) {
alarmModeDetailDTO!.notification = value;
},
),
),*/
ExpansionTile(
title: Text(
"Devices",
style: TextStyle(
fontSize: 18.0,
fontWeight: FontWeight.bold
),
),
children: [
for(var device in roomDetailDTO!.devices!)
ExpansionTile(
title: Text(device.name!),
children: <Widget>[
ListTile(
title: Text("type: "+ (device.type != null ? device.type!.value : 'no type') ),
),
ListTile(
title: Text("status: "+ device.status.toString()),
),
ListTile(
title: Text("last update date: "+ device.lastStateDate!.toLocal().toString()),
),
ListTile(
title: Text("lastState: "+ (device.lastState != null ? device.lastState! : 'no data')),
)
],
),
],
),
],
),
);
} else {
return const LoadingCommon();
}
}
)
);
}
}

View File

@ -7,6 +7,7 @@ import 'package:myhomie_app/Components/Custom_Navigation_Bar/custom_nav_item.dar
import 'package:myhomie_app/Helpers/MQTTHelper.dart'; import 'package:myhomie_app/Helpers/MQTTHelper.dart';
import 'package:myhomie_app/Screens/Debug/DebugPage.dart'; import 'package:myhomie_app/Screens/Debug/DebugPage.dart';
import 'package:myhomie_app/Screens/Main/Automations/automations.dart'; import 'package:myhomie_app/Screens/Main/Automations/automations.dart';
import 'package:myhomie_app/Screens/Main/Devices/devices.dart';
import 'package:myhomie_app/app_context.dart'; import 'package:myhomie_app/app_context.dart';
import 'package:myhomie_app/constants.dart'; import 'package:myhomie_app/constants.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -62,8 +63,9 @@ class _MainPageState extends State<MainPage> {
HomeScreen(), HomeScreen(),
SecurityScreen(), SecurityScreen(),
AutomationsScreen(), AutomationsScreen(),
DevicesScreen(),
EnergyScreen(), EnergyScreen(),
ProfileScreen(), //ProfileScreen(),
], ],
), ),
drawer: Drawer( drawer: Drawer(

View File

@ -0,0 +1,211 @@
import 'dart:convert';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:mycore_api/api.dart';
import 'package:mycore_api/api.dart' as API;
import 'package:myhomie_app/Components/Alarms/getCurrentAlarmModeIcon.dart';
import 'package:myhomie_app/Components/Custom_Navigation_Bar/CustomAppBar.dart';
import 'package:myhomie_app/Components/check_input_container.dart';
import 'package:myhomie_app/Components/loading_common.dart';
import 'package:myhomie_app/Components/string_input_container.dart';
import 'package:myhomie_app/Models/homieContext.dart';
import 'package:myhomie_app/app_context.dart';
import 'package:myhomie_app/constants.dart';
import 'package:provider/provider.dart';
class AlarmDetailPage extends StatefulWidget {
const AlarmDetailPage({Key? key, required this.alarmMode}) : super(key: key);
final AlarmModeDTO alarmMode;
@override
State<AlarmDetailPage> createState() => _AlarmDetailPageState();
}
class _AlarmDetailPageState extends State<AlarmDetailPage> {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
AlarmModeDetailDTO? alarmModeDetailDTO;
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
final appContext = Provider.of<AppContext>(context);
Size size = MediaQuery.of(context).size;
//final notchInset = MediaQuery.of(context).padding;
HomieAppContext homieAppContext = appContext.getContext();
return Scaffold(
key: _scaffoldKey,
appBar: CustomAppBar(
title: widget.alarmMode.name!,
titleIcon: getAlarmModeIcon(widget.alarmMode),
isTextSizeButton: true,
),
body: FutureBuilder(
future: homieAppContext.clientAPI.alarmApi!.alarmGetDetail(widget.alarmMode.id!),
builder: (context, AsyncSnapshot<AlarmModeDetailDTO?> snapshot) {
if(snapshot.data != null ) {
alarmModeDetailDTO = snapshot.data;
return SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
if(!alarmModeDetailDTO!.isDefault!)
SizedBox(
width: size.width *1.1,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: StringInputContainer(
label: "Nom:",
color: kMainColor,
textColor: Colors.white,
initialValue: alarmModeDetailDTO!.name,
onChanged: (String value) {
setState(() {
alarmModeDetailDTO!.name = value;
// TODO SAVE or not
});
},
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: CheckInputContainer(
icon: Icons.notifications_active,
label: "Notification :",
fontSize: 20,
isChecked: alarmModeDetailDTO!.notification!,
onChanged: (bool value) {
alarmModeDetailDTO!.notification = value;
},
),
),
ExpansionTile(
title: Text(
"Triggers",
style: TextStyle(
fontSize: 18.0,
fontWeight: FontWeight.bold
),
),
children: [
for(var trigger in alarmModeDetailDTO!.triggers!)
if(alarmModeDetailDTO!.devices!.where((d) => d.id == trigger.deviceId).isNotEmpty)
ExpansionTile(
title: Text(alarmModeDetailDTO!.devices!.firstWhere((d) => d.id == trigger.deviceId).name!),
children: <Widget>[
ListTile(
title: Text("name: "+trigger.stateName! + " - " + "value: "+ trigger.stateValue!),
)
],
),
ListTile(
title: Text("Ajouter +", style: TextStyle(), textAlign: TextAlign.center),
tileColor: Colors.lightGreen,
onTap: () {
// Show popup ajout
debugPrint("Add device to trigger popup");
},
)
],
),
ExpansionTile(
title: Text(
"Actions",
style: TextStyle(
fontSize: 18.0,
fontWeight: FontWeight.bold
),
),
children: [
for(var action in alarmModeDetailDTO!.actions!)
actionTile(action),
ListTile(
title: Text("Ajouter +", style: TextStyle(), textAlign: TextAlign.center),
tileColor: Colors.lightGreen,
onTap: () {
// Show popup ajout
debugPrint("Add device to trigger popup");
},
)
],
),
Text("Actions"),
for(var device in alarmModeDetailDTO!.devices!.where((d) => alarmModeDetailDTO!.actions!.map((t)=> t.deviceId).contains(d.id)))
Text(device.name!),
Text(alarmModeDetailDTO!.actions!.toString()),
],
),
);
} else {
return const LoadingCommon();
}
}
)
);
}
actionTile(API.Action action) {
switch(action.type) {
case ActionType.DELAY:
return ListTile(
title: Text(action.type.toString()),
);
case ActionType.DEVICE:
return ExpansionTile(
title: Text(action.type.toString()),
children: [
if(alarmModeDetailDTO!.devices!.where((d) => d.id == action.deviceId).isNotEmpty)
ExpansionTile(
title: Text(alarmModeDetailDTO!.devices!.firstWhere((d) => d.id == action.deviceId).name!),
children: [
ListTile(
title: Text(action.states.toString())
),
],
)
],
);
case ActionType.GROUP:
return ListTile(
title: Text(action.type.toString()),
);
case ActionType.HTTP:
return ListTile(
title: Text(action.type.toString()),
);
case ActionType.MQTT:
return ExpansionTile(
title: Text(action.type.toString()),
children: [
ListTile(
title: Text(action.rawRequest!),
)
],
);
case ActionType.zIGBEE2MQTT:
return ListTile(
title: Text(action.type.toString()),
);
}
}
}

View File

@ -0,0 +1,89 @@
import 'package:flutter/material.dart';
import 'package:mycore_api/api.dart';
import 'package:myhomie_app/Components/Alarms/getCurrentAlarmModeIcon.dart';
import 'package:myhomie_app/Models/homieContext.dart';
import 'package:myhomie_app/constants.dart';
Future<String?> showChangeAlarmModePopup(List<AlarmModeDTO> allAlarmModes, HomieAppContext homieAppContext, BuildContext context, Size size) {
return showDialog(
builder: (BuildContext dialogContext) => AlertDialog(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10.0))
),
content: SingleChildScrollView(
child: Column(
children: [
SizedBox(
height: size.height * 0.5,
width: size.width * 0.95,
child: Center(
child: Padding(
padding: const EdgeInsets.only(left:8.0, right: 8.0, bottom: 8.0, top: 8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Text("Changer le mode d'alarme courante"),
),
SingleChildScrollView(
child: Container(
height: size.height*0.4,
//color: Colors.orange,
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
for(var alarmMode in allAlarmModes)
SizedBox(
width: size.width * 0.5,
height: size.height * 0.05,
child: InkWell(
onTap: () {
Navigator.pop(dialogContext, alarmMode.id);
},
child: Container(
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(20.0),
border: Border.all(
color: kBackgroundSecondGrey.withOpacity(0.35),
width: 0.2,
),
boxShadow: [
BoxShadow(
color: kMainColor.withOpacity(0.35),
//spreadRadius: 0.15,
blurRadius: 5,
offset: const Offset(0, 10), // changes position of shadow
),
],
),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text(alarmMode.name!),
Icon(getAlarmModeIcon(alarmMode)),
],
),
),
),
)
],
)
),
)
],
),
),
),
),
],
),
),
contentPadding: EdgeInsets.zero,
), context: context
);
}

View File

@ -1,5 +1,12 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mycore_api/api.dart';
import 'package:myhomie_app/Components/Alarms/getCurrentAlarmModeIcon.dart';
import 'package:myhomie_app/Components/loading_common.dart';
import 'package:myhomie_app/Models/homieContext.dart';
import 'package:myhomie_app/Screens/Main/Security/alarmDetailPage.dart';
import 'package:myhomie_app/Screens/Main/Security/changeAlarmMode.dart';
import 'package:myhomie_app/app_context.dart'; import 'package:myhomie_app/app_context.dart';
import 'package:myhomie_app/constants.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class SecurityScreen extends StatefulWidget { class SecurityScreen extends StatefulWidget {
@ -11,7 +18,8 @@ class SecurityScreen extends StatefulWidget {
class _SecurityScreenState extends State<SecurityScreen> { class _SecurityScreenState extends State<SecurityScreen> {
bool isLoading = true; bool isLoading = true;
//List<Message> messages; List<AlarmModeDTO>? allAlarmModes;
AlarmModeDTO? currentAlarmMode;
@override @override
void initState() { void initState() {
@ -22,31 +30,8 @@ class _SecurityScreenState extends State<SecurityScreen> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size; Size size = MediaQuery.of(context).size;
final appContext = Provider.of<AppContext>(context); final appContext = Provider.of<AppContext>(context);
HomieAppContext homieAppContext = appContext.getContext();
return interfaceElements();
/*if(appContext.getContext().feed != null) {
return interfaceElements();
} else {
return FutureBuilder(
future: Message.getMessages(this.messages, appContext, false, true),
builder: (context, AsyncSnapshot<List<Message>> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return interfaceElements();
} else if (snapshot.connectionState == ConnectionState.none) {
print('ConnectionState.none');
return Text("No data");
} else {
return Container(height: size.height * 0.2, child: Loading());
}
}
);
}*/
}
interfaceElements() {
Size size = MediaQuery.of(context).size;
final appContext = Provider.of<AppContext>(context);
return RefreshIndicator( return RefreshIndicator(
color: Theme.of(context).primaryColor, color: Theme.of(context).primaryColor,
displacement: 20, displacement: 20,
@ -55,16 +40,98 @@ class _SecurityScreenState extends State<SecurityScreen> {
//await Message.getMessages(this.messages, appContext, true, true); //await Message.getMessages(this.messages, appContext, true, true);
}, },
child: Container( child: Container(
height: size.height * 0.8, height: size.height * 0.842,
child: SingleChildScrollView( //child: SingleChildScrollView(
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [ children: [
Text("TODO Security") FutureBuilder(
], future: homieAppContext.clientAPI.alarmApi!.alarmGetAll(homieAppContext.homeId!),
), builder: (context, AsyncSnapshot<List<AlarmModeDTO>?> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
allAlarmModes = snapshot.data;
currentAlarmMode = allAlarmModes!.where((am) => am.activated!).first;
return Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
child: Container(
width: size.width * 0.6,
height: size.height * 0.1,
decoration: alarmDecoration(currentAlarmMode!),
child: InkWell(
onTap: () async {
var result = await showChangeAlarmModePopup(allAlarmModes!, homieAppContext, context, size);
if(result != null && currentAlarmMode!.id != result) {
// update current alarmMode
try{
var resultId = await homieAppContext.clientAPI.alarmApi!.alarmActivate(result);
if(resultId != null) {
//allAlarmModes!.firstWhere((alarmMode) => alarmMode.id == resultId);
setState(() {
});
}
} catch(e) {
debugPrint("An error occured during alarm mode activation - " + e.toString());
}
}
},
onLongPress: () {
if(currentAlarmMode!.type! != AlarmType.desarmed) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AlarmDetailPage(
alarmMode: currentAlarmMode!,
),
),
);
}
},
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text(currentAlarmMode!.name!),
Icon(getAlarmModeIcon(currentAlarmMode!)),
],
),
),
),
),
);
} else if (snapshot.connectionState == ConnectionState.none) {
print('ConnectionState.none');
return Text("No data");
} else {
return Container(height: size.height * 0.2, child: LoadingCommon());
}
}
),
Text("TODO Cameras"),
],
), ),
//),
), ),
); );
} }
} }
alarmDecoration(AlarmModeDTO alarmModeDTO) {
return BoxDecoration(
color: alarmModeDTO.activated! && alarmModeDTO.type == AlarmType.desarmed ? Colors.white : Colors.red.withOpacity(0.6),
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(20.0),
border: Border.all(
color: kBackgroundSecondGrey.withOpacity(0.35),
width: 0.2,
),
boxShadow: [
BoxShadow(
color: kMainColor.withOpacity(0.35),
//spreadRadius: 0.15,
blurRadius: 5,
offset: const Offset(0, 15), // changes position of shadow
),
],
);
}

View File

@ -22,6 +22,8 @@ class Index with ChangeNotifier {
return "Security"; return "Security";
case NavItemIcon.automations: case NavItemIcon.automations:
return "Automations"; return "Automations";
case NavItemIcon.devices:
return "Devices";
case NavItemIcon.energy: case NavItemIcon.energy:
return "Energy"; return "Energy";
case NavItemIcon.profile: case NavItemIcon.profile:

View File

@ -4186,6 +4186,11 @@ components:
nullable: true nullable: true
items: items:
$ref: '#/components/schemas/Trigger' $ref: '#/components/schemas/Trigger'
actions:
type: array
nullable: true
items:
$ref: '#/components/schemas/Action'
devices: devices:
type: array type: array
nullable: true nullable: true
@ -4442,6 +4447,11 @@ components:
nullable: true nullable: true
items: items:
type: string type: string
devices:
type: array
nullable: true
items:
$ref: '#/components/schemas/DeviceDetailDTO'
Condition: Condition:
type: object type: object
additionalProperties: false additionalProperties: false

View File

@ -1,4 +1,6 @@
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:myhomie_app/Helpers/PushNotificationService.dart';
import 'package:myhomie_app/client.dart'; import 'package:myhomie_app/client.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -25,6 +27,7 @@ void main() async {
print(localContext); print(localContext);
} else { } else {
print("NO LOCAL DB !"); print("NO LOCAL DB !");
localContext = HomieAppContext();
} }
initialRoute = isLogged ? '/home' : '/login'; initialRoute = isLogged ? '/home' : '/login';
@ -47,10 +50,13 @@ class MyApp extends StatefulWidget {
} }
class _MyAppState extends State<MyApp> { class _MyAppState extends State<MyApp> {
//FirebaseMessaging _firebaseMessaging = FirebaseMessaging();
//HomieAppContext homieAppContext; //HomieAppContext homieAppContext;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final pushNotificationService = PushNotificationService();
pushNotificationService.initialise(widget.homieAppContext, context: context);
return ChangeNotifierProvider<AppContext>( return ChangeNotifierProvider<AppContext>(
create: (_) => AppContext(widget.homieAppContext), create: (_) => AppContext(widget.homieAppContext),
child: MaterialApp( child: MaterialApp(

View File

@ -5,8 +5,12 @@
import FlutterMacOS import FlutterMacOS
import Foundation import Foundation
import firebase_core
import firebase_messaging
import sqflite import sqflite
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin"))
FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
} }

View File

@ -18,6 +18,7 @@ Name | Type | Description | Notes
**createdDate** | [**DateTime**](DateTime.md) | | [optional] **createdDate** | [**DateTime**](DateTime.md) | | [optional]
**updatedDate** | [**DateTime**](DateTime.md) | | [optional] **updatedDate** | [**DateTime**](DateTime.md) | | [optional]
**triggers** | [**List<Trigger>**](Trigger.md) | | [optional] [default to const []] **triggers** | [**List<Trigger>**](Trigger.md) | | [optional] [default to const []]
**actions** | [**List<Action>**](Action.md) | | [optional] [default to const []]
**devices** | [**List<DeviceDetailDTO>**](DeviceDetailDTO.md) | | [optional] [default to const []] **devices** | [**List<DeviceDetailDTO>**](DeviceDetailDTO.md) | | [optional] [default to const []]
**programmedMode** | [**OneOfProgrammedMode**](OneOfProgrammedMode.md) | | [optional] **programmedMode** | [**OneOfProgrammedMode**](OneOfProgrammedMode.md) | | [optional]
**geolocalizedMode** | [**OneOfGeolocalizedMode**](OneOfGeolocalizedMode.md) | | [optional] **geolocalizedMode** | [**OneOfGeolocalizedMode**](OneOfGeolocalizedMode.md) | | [optional]

View File

@ -9,6 +9,7 @@ import 'package:mycore_api/api.dart';
Name | Type | Description | Notes Name | Type | Description | Notes
------------ | ------------- | ------------- | ------------- ------------ | ------------- | ------------- | -------------
**triggers** | [**List<Trigger>**](Trigger.md) | | [optional] [default to const []] **triggers** | [**List<Trigger>**](Trigger.md) | | [optional] [default to const []]
**actions** | [**List<Action>**](Action.md) | | [optional] [default to const []]
**devices** | [**List<DeviceDetailDTO>**](DeviceDetailDTO.md) | | [optional] [default to const []] **devices** | [**List<DeviceDetailDTO>**](DeviceDetailDTO.md) | | [optional] [default to const []]
**programmedMode** | [**OneOfProgrammedMode**](OneOfProgrammedMode.md) | | [optional] **programmedMode** | [**OneOfProgrammedMode**](OneOfProgrammedMode.md) | | [optional]
**geolocalizedMode** | [**OneOfGeolocalizedMode**](OneOfGeolocalizedMode.md) | | [optional] **geolocalizedMode** | [**OneOfGeolocalizedMode**](OneOfGeolocalizedMode.md) | | [optional]

View File

@ -18,6 +18,7 @@ Name | Type | Description | Notes
**conditions** | [**List<Condition>**](Condition.md) | | [optional] [default to const []] **conditions** | [**List<Condition>**](Condition.md) | | [optional] [default to const []]
**actions** | [**List<Action>**](Action.md) | | [optional] [default to const []] **actions** | [**List<Action>**](Action.md) | | [optional] [default to const []]
**devicesIds** | **List<String>** | | [optional] [default to const []] **devicesIds** | **List<String>** | | [optional] [default to const []]
**devices** | [**List<DeviceDetailDTO>**](DeviceDetailDTO.md) | | [optional] [default to const []]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@ -12,6 +12,7 @@ Name | Type | Description | Notes
**conditions** | [**List<Condition>**](Condition.md) | | [optional] [default to const []] **conditions** | [**List<Condition>**](Condition.md) | | [optional] [default to const []]
**actions** | [**List<Action>**](Action.md) | | [optional] [default to const []] **actions** | [**List<Action>**](Action.md) | | [optional] [default to const []]
**devicesIds** | **List<String>** | | [optional] [default to const []] **devicesIds** | **List<String>** | | [optional] [default to const []]
**devices** | [**List<DeviceDetailDTO>**](DeviceDetailDTO.md) | | [optional] [default to const []]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@ -23,6 +23,7 @@ class AlarmModeDetailDTO {
this.createdDate, this.createdDate,
this.updatedDate, this.updatedDate,
this.triggers = const [], this.triggers = const [],
this.actions = const [],
this.devices = const [], this.devices = const [],
this.programmedMode, this.programmedMode,
this.geolocalizedMode, this.geolocalizedMode,
@ -84,6 +85,8 @@ class AlarmModeDetailDTO {
List<Trigger>? triggers; List<Trigger>? triggers;
List<Action>? actions;
List<DeviceDetailDTO>? devices; List<DeviceDetailDTO>? devices;
ProgrammedMode? programmedMode; ProgrammedMode? programmedMode;
@ -102,6 +105,7 @@ class AlarmModeDetailDTO {
other.createdDate == createdDate && other.createdDate == createdDate &&
other.updatedDate == updatedDate && other.updatedDate == updatedDate &&
other.triggers == triggers && other.triggers == triggers &&
other.actions == actions &&
other.devices == devices && other.devices == devices &&
other.programmedMode == programmedMode && other.programmedMode == programmedMode &&
other.geolocalizedMode == geolocalizedMode; other.geolocalizedMode == geolocalizedMode;
@ -119,12 +123,13 @@ class AlarmModeDetailDTO {
(createdDate == null ? 0 : createdDate!.hashCode) + (createdDate == null ? 0 : createdDate!.hashCode) +
(updatedDate == null ? 0 : updatedDate!.hashCode) + (updatedDate == null ? 0 : updatedDate!.hashCode) +
(triggers == null ? 0 : triggers!.hashCode) + (triggers == null ? 0 : triggers!.hashCode) +
(actions == null ? 0 : actions!.hashCode) +
(devices == null ? 0 : devices!.hashCode) + (devices == null ? 0 : devices!.hashCode) +
(programmedMode == null ? 0 : programmedMode!.hashCode) + (programmedMode == null ? 0 : programmedMode!.hashCode) +
(geolocalizedMode == null ? 0 : geolocalizedMode!.hashCode); (geolocalizedMode == null ? 0 : geolocalizedMode!.hashCode);
@override @override
String toString() => 'AlarmModeDetailDTO[id=$id, homeId=$homeId, name=$name, type=$type, activated=$activated, isDefault=$isDefault, notification=$notification, createdDate=$createdDate, updatedDate=$updatedDate, triggers=$triggers, devices=$devices, programmedMode=$programmedMode, geolocalizedMode=$geolocalizedMode]'; String toString() => 'AlarmModeDetailDTO[id=$id, homeId=$homeId, name=$name, type=$type, activated=$activated, isDefault=$isDefault, notification=$notification, createdDate=$createdDate, updatedDate=$updatedDate, triggers=$triggers, actions=$actions, devices=$devices, programmedMode=$programmedMode, geolocalizedMode=$geolocalizedMode]';
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final _json = <String, dynamic>{}; final _json = <String, dynamic>{};
@ -158,6 +163,9 @@ class AlarmModeDetailDTO {
if (triggers != null) { if (triggers != null) {
_json[r'triggers'] = triggers; _json[r'triggers'] = triggers;
} }
if (actions != null) {
_json[r'actions'] = actions;
}
if (devices != null) { if (devices != null) {
_json[r'devices'] = devices; _json[r'devices'] = devices;
} }
@ -199,6 +207,7 @@ class AlarmModeDetailDTO {
createdDate: mapDateTime(json, r'createdDate', ''), createdDate: mapDateTime(json, r'createdDate', ''),
updatedDate: mapDateTime(json, r'updatedDate', ''), updatedDate: mapDateTime(json, r'updatedDate', ''),
triggers: Trigger.listFromJson(json[r'triggers']) ?? const [], triggers: Trigger.listFromJson(json[r'triggers']) ?? const [],
actions: Action.listFromJson(json[r'actions']) ?? const [],
devices: DeviceDetailDTO.listFromJson(json[r'devices']) ?? const [], devices: DeviceDetailDTO.listFromJson(json[r'devices']) ?? const [],
programmedMode: ProgrammedMode.fromJson(json[r'programmedMode']), programmedMode: ProgrammedMode.fromJson(json[r'programmedMode']),
geolocalizedMode: GeolocalizedMode.fromJson(json[r'geolocalizedMode']), geolocalizedMode: GeolocalizedMode.fromJson(json[r'geolocalizedMode']),

View File

@ -14,6 +14,7 @@ class AlarmModeDetailDTOAllOf {
/// Returns a new [AlarmModeDetailDTOAllOf] instance. /// Returns a new [AlarmModeDetailDTOAllOf] instance.
AlarmModeDetailDTOAllOf({ AlarmModeDetailDTOAllOf({
this.triggers = const [], this.triggers = const [],
this.actions = const [],
this.devices = const [], this.devices = const [],
this.programmedMode, this.programmedMode,
this.geolocalizedMode, this.geolocalizedMode,
@ -21,6 +22,8 @@ class AlarmModeDetailDTOAllOf {
List<Trigger>? triggers; List<Trigger>? triggers;
List<Action>? actions;
List<DeviceDetailDTO>? devices; List<DeviceDetailDTO>? devices;
ProgrammedMode? programmedMode; ProgrammedMode? programmedMode;
@ -30,6 +33,7 @@ class AlarmModeDetailDTOAllOf {
@override @override
bool operator ==(Object other) => identical(this, other) || other is AlarmModeDetailDTOAllOf && bool operator ==(Object other) => identical(this, other) || other is AlarmModeDetailDTOAllOf &&
other.triggers == triggers && other.triggers == triggers &&
other.actions == actions &&
other.devices == devices && other.devices == devices &&
other.programmedMode == programmedMode && other.programmedMode == programmedMode &&
other.geolocalizedMode == geolocalizedMode; other.geolocalizedMode == geolocalizedMode;
@ -38,18 +42,22 @@ class AlarmModeDetailDTOAllOf {
int get hashCode => int get hashCode =>
// ignore: unnecessary_parenthesis // ignore: unnecessary_parenthesis
(triggers == null ? 0 : triggers!.hashCode) + (triggers == null ? 0 : triggers!.hashCode) +
(actions == null ? 0 : actions!.hashCode) +
(devices == null ? 0 : devices!.hashCode) + (devices == null ? 0 : devices!.hashCode) +
(programmedMode == null ? 0 : programmedMode!.hashCode) + (programmedMode == null ? 0 : programmedMode!.hashCode) +
(geolocalizedMode == null ? 0 : geolocalizedMode!.hashCode); (geolocalizedMode == null ? 0 : geolocalizedMode!.hashCode);
@override @override
String toString() => 'AlarmModeDetailDTOAllOf[triggers=$triggers, devices=$devices, programmedMode=$programmedMode, geolocalizedMode=$geolocalizedMode]'; String toString() => 'AlarmModeDetailDTOAllOf[triggers=$triggers, actions=$actions, devices=$devices, programmedMode=$programmedMode, geolocalizedMode=$geolocalizedMode]';
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final _json = <String, dynamic>{}; final _json = <String, dynamic>{};
if (triggers != null) { if (triggers != null) {
_json[r'triggers'] = triggers; _json[r'triggers'] = triggers;
} }
if (actions != null) {
_json[r'actions'] = actions;
}
if (devices != null) { if (devices != null) {
_json[r'devices'] = devices; _json[r'devices'] = devices;
} }
@ -82,6 +90,7 @@ class AlarmModeDetailDTOAllOf {
return AlarmModeDetailDTOAllOf( return AlarmModeDetailDTOAllOf(
triggers: Trigger.listFromJson(json[r'triggers']) ?? const [], triggers: Trigger.listFromJson(json[r'triggers']) ?? const [],
actions: Action.listFromJson(json[r'actions']) ?? const [],
devices: DeviceDetailDTO.listFromJson(json[r'devices']) ?? const [], devices: DeviceDetailDTO.listFromJson(json[r'devices']) ?? const [],
programmedMode: ProgrammedMode.fromJson(json[r'programmedMode']), programmedMode: ProgrammedMode.fromJson(json[r'programmedMode']),
geolocalizedMode: GeolocalizedMode.fromJson(json[r'geolocalizedMode']), geolocalizedMode: GeolocalizedMode.fromJson(json[r'geolocalizedMode']),

View File

@ -23,6 +23,7 @@ class AutomationDetailDTO {
this.conditions = const [], this.conditions = const [],
this.actions = const [], this.actions = const [],
this.devicesIds = const [], this.devicesIds = const [],
this.devices = const [],
}); });
String? id; String? id;
@ -63,6 +64,8 @@ class AutomationDetailDTO {
List<String>? devicesIds; List<String>? devicesIds;
List<DeviceDetailDTO>? devices;
@override @override
bool operator ==(Object other) => identical(this, other) || other is AutomationDetailDTO && bool operator ==(Object other) => identical(this, other) || other is AutomationDetailDTO &&
other.id == id && other.id == id &&
@ -74,7 +77,8 @@ class AutomationDetailDTO {
other.triggers == triggers && other.triggers == triggers &&
other.conditions == conditions && other.conditions == conditions &&
other.actions == actions && other.actions == actions &&
other.devicesIds == devicesIds; other.devicesIds == devicesIds &&
other.devices == devices;
@override @override
int get hashCode => int get hashCode =>
@ -88,10 +92,11 @@ class AutomationDetailDTO {
(triggers == null ? 0 : triggers!.hashCode) + (triggers == null ? 0 : triggers!.hashCode) +
(conditions == null ? 0 : conditions!.hashCode) + (conditions == null ? 0 : conditions!.hashCode) +
(actions == null ? 0 : actions!.hashCode) + (actions == null ? 0 : actions!.hashCode) +
(devicesIds == null ? 0 : devicesIds!.hashCode); (devicesIds == null ? 0 : devicesIds!.hashCode) +
(devices == null ? 0 : devices!.hashCode);
@override @override
String toString() => 'AutomationDetailDTO[id=$id, name=$name, active=$active, homeId=$homeId, createdDate=$createdDate, updatedDate=$updatedDate, triggers=$triggers, conditions=$conditions, actions=$actions, devicesIds=$devicesIds]'; String toString() => 'AutomationDetailDTO[id=$id, name=$name, active=$active, homeId=$homeId, createdDate=$createdDate, updatedDate=$updatedDate, triggers=$triggers, conditions=$conditions, actions=$actions, devicesIds=$devicesIds, devices=$devices]';
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final _json = <String, dynamic>{}; final _json = <String, dynamic>{};
@ -125,6 +130,9 @@ class AutomationDetailDTO {
if (devicesIds != null) { if (devicesIds != null) {
_json[r'devicesIds'] = devicesIds; _json[r'devicesIds'] = devicesIds;
} }
if (devices != null) {
_json[r'devices'] = devices;
}
return _json; return _json;
} }
@ -159,6 +167,7 @@ class AutomationDetailDTO {
devicesIds: json[r'devicesIds'] is List devicesIds: json[r'devicesIds'] is List
? (json[r'devicesIds'] as List).cast<String>() ? (json[r'devicesIds'] as List).cast<String>()
: const [], : const [],
devices: DeviceDetailDTO.listFromJson(json[r'devices']) ?? const [],
); );
} }
return null; return null;

View File

@ -17,6 +17,7 @@ class AutomationDetailDTOAllOf {
this.conditions = const [], this.conditions = const [],
this.actions = const [], this.actions = const [],
this.devicesIds = const [], this.devicesIds = const [],
this.devices = const [],
}); });
List<Trigger>? triggers; List<Trigger>? triggers;
@ -27,12 +28,15 @@ class AutomationDetailDTOAllOf {
List<String>? devicesIds; List<String>? devicesIds;
List<DeviceDetailDTO>? devices;
@override @override
bool operator ==(Object other) => identical(this, other) || other is AutomationDetailDTOAllOf && bool operator ==(Object other) => identical(this, other) || other is AutomationDetailDTOAllOf &&
other.triggers == triggers && other.triggers == triggers &&
other.conditions == conditions && other.conditions == conditions &&
other.actions == actions && other.actions == actions &&
other.devicesIds == devicesIds; other.devicesIds == devicesIds &&
other.devices == devices;
@override @override
int get hashCode => int get hashCode =>
@ -40,10 +44,11 @@ class AutomationDetailDTOAllOf {
(triggers == null ? 0 : triggers!.hashCode) + (triggers == null ? 0 : triggers!.hashCode) +
(conditions == null ? 0 : conditions!.hashCode) + (conditions == null ? 0 : conditions!.hashCode) +
(actions == null ? 0 : actions!.hashCode) + (actions == null ? 0 : actions!.hashCode) +
(devicesIds == null ? 0 : devicesIds!.hashCode); (devicesIds == null ? 0 : devicesIds!.hashCode) +
(devices == null ? 0 : devices!.hashCode);
@override @override
String toString() => 'AutomationDetailDTOAllOf[triggers=$triggers, conditions=$conditions, actions=$actions, devicesIds=$devicesIds]'; String toString() => 'AutomationDetailDTOAllOf[triggers=$triggers, conditions=$conditions, actions=$actions, devicesIds=$devicesIds, devices=$devices]';
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final _json = <String, dynamic>{}; final _json = <String, dynamic>{};
@ -59,6 +64,9 @@ class AutomationDetailDTOAllOf {
if (devicesIds != null) { if (devicesIds != null) {
_json[r'devicesIds'] = devicesIds; _json[r'devicesIds'] = devicesIds;
} }
if (devices != null) {
_json[r'devices'] = devices;
}
return _json; return _json;
} }
@ -87,6 +95,7 @@ class AutomationDetailDTOAllOf {
devicesIds: json[r'devicesIds'] is List devicesIds: json[r'devicesIds'] is List
? (json[r'devicesIds'] as List).cast<String>() ? (json[r'devicesIds'] as List).cast<String>()
: const [], : const [],
devices: DeviceDetailDTO.listFromJson(json[r'devices']) ?? const [],
); );
} }
return null; return null;

View File

@ -9,6 +9,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "48.0.0" version: "48.0.0"
_flutterfire_internals:
dependency: transitive
description:
name: _flutterfire_internals
sha256: "5dce45a06d386358334eb1689108db6455d90ceb0d75848d5f4819283d4ee2b8"
url: "https://pub.dev"
source: hosted
version: "1.3.4"
analyzer: analyzer:
dependency: transitive dependency: transitive
description: description:
@ -33,6 +41,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.10.0" version: "2.10.0"
auto_size_text:
dependency: "direct main"
description:
name: auto_size_text
sha256: "3f5261cd3fb5f2a9ab4e2fc3fba84fd9fcaac8821f20a1d4e71f557521b22599"
url: "https://pub.dev"
source: hosted
version: "3.0.0"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
@ -209,6 +225,54 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.1.4" version: "6.1.4"
firebase_core:
dependency: transitive
description:
name: firebase_core
sha256: "2e9324f719e90200dc7d3c4f5d2abc26052f9f2b995d3b6626c47a0dfe1c8192"
url: "https://pub.dev"
source: hosted
version: "2.15.0"
firebase_core_platform_interface:
dependency: transitive
description:
name: firebase_core_platform_interface
sha256: b63e3be6c96ef5c33bdec1aab23c91eb00696f6452f0519401d640938c94cba2
url: "https://pub.dev"
source: hosted
version: "4.8.0"
firebase_core_web:
dependency: transitive
description:
name: firebase_core_web
sha256: "0fd5c4b228de29b55fac38aed0d9e42514b3d3bd47675de52bf7f8fccaf922fa"
url: "https://pub.dev"
source: hosted
version: "2.6.0"
firebase_messaging:
dependency: "direct main"
description:
name: firebase_messaging
sha256: "8ac91d83a028eef050de770f1dc98421e215714d245f34de7b154d436676fbd0"
url: "https://pub.dev"
source: hosted
version: "14.6.5"
firebase_messaging_platform_interface:
dependency: transitive
description:
name: firebase_messaging_platform_interface
sha256: b2995e3640efb646e9ebf0e2fa50dea84895f0746a31d7e3af0e5e009a533a1a
url: "https://pub.dev"
source: hosted
version: "4.5.4"
firebase_messaging_web:
dependency: transitive
description:
name: firebase_messaging_web
sha256: "5d8446a28339124a2cb4f57a6ca454a3aca7d0c5c0cdfa5707afb192f7c830a7"
url: "https://pub.dev"
source: hosted
version: "3.5.4"
fixnum: fixnum:
dependency: transitive dependency: transitive
description: description:
@ -455,6 +519,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.1.0" version: "5.1.0"
plugin_platform_interface:
dependency: transitive
description:
name: plugin_platform_interface
sha256: "43798d895c929056255600343db8f049921cbec94d31ec87f1dc5c16c01935dd"
url: "https://pub.dev"
source: hosted
version: "2.1.5"
pool: pool:
dependency: transitive dependency: transitive
description: description:

View File

@ -41,6 +41,8 @@ dependencies:
# The following adds the Cupertino Icons font to your application. # The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons. # Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.0 cupertino_icons: ^1.0.0
auto_size_text: ^3.0.0
firebase_messaging: ^14.6.5
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View File

@ -6,6 +6,9 @@
#include "generated_plugin_registrant.h" #include "generated_plugin_registrant.h"
#include <firebase_core/firebase_core_plugin_c_api.h>
void RegisterPlugins(flutter::PluginRegistry* registry) { void RegisterPlugins(flutter::PluginRegistry* registry) {
FirebaseCorePluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FirebaseCorePluginCApi"));
} }

View File

@ -3,6 +3,7 @@
# #
list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_PLUGIN_LIST
firebase_core
) )
list(APPEND FLUTTER_FFI_PLUGIN_LIST list(APPEND FLUTTER_FFI_PLUGIN_LIST