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 packages pub get
flutter pub run build_runner build --delete-conflicting-outputs
Le fichier est dans le projet.

View File

@ -24,9 +24,10 @@ if (flutterVersionName == null) {
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
apply plugin: 'com.google.gms.google-services'
android {
compileSdkVersion 32
compileSdkVersion 33
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
@ -110,4 +111,14 @@ flutter {
dependencies {
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"
package="be.myhomie.myhomie_app">
package="be.unov.myhomie">
<!-- Flutter needs it to communicate with the running application
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"
package="be.myhomie.myhomie_app">
package="be.unov.myhomie">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:label="MyHomie"
android:usesCleartextTraffic="true"
android:usesCleartextTraffic="true"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
@ -20,6 +20,9 @@
android:name="io.flutter.embedding.android.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
Drawable until Flutter paints its first frame, then this splash
screen fades out. A splash screen is useful to avoid any visual
@ -33,11 +36,23 @@
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="FLUTTER_NOTIFICATION_CLICK" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
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>
</manifest>

View File

@ -1,4 +1,4 @@
package be.myhomie.myhomie_app
package be.unov.myhomie
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"
package="be.myhomie.myhomie_app">
package="be.unov.myhomie">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->

View File

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

View File

@ -8,6 +8,7 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
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,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
CustomNavItem(setPage: setPage, icon: NavItemIcon.energy, id: 3),
CustomNavItem(setPage: setPage, icon: NavItemIcon.profile, id: 4),
CustomNavItem(setPage: setPage, icon: NavItemIcon.devices, id: 3),
CustomNavItem(setPage: setPage, icon: NavItemIcon.energy, id: 4),
],
),
),

View File

@ -54,22 +54,28 @@ class CustomNavItem extends StatelessWidget {
size: 25,
color: Colors.white,
);
case 'energy':
case 'devices':
return Icon(
Icons.power,
Icons.devices_other,
size: 25,
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(
Icons.person,
size: 25,
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
}
}
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 Color color, textColor, iconColor;
final int? maxLength;
final double? fontSize;
const RoundedInputField({
Key? key,
this.hintText,
@ -19,6 +20,7 @@ class RoundedInputField extends StatelessWidget {
this.iconColor = kTitleTextColor, // TODO
this.onChanged,
this.maxLength, // 50
this.fontSize = 20,
}) : super(key: key);
@override
@ -30,7 +32,7 @@ class RoundedInputField extends StatelessWidget {
initialValue: initialValue,
cursorColor: textColor,
maxLength: maxLength,
style: TextStyle(fontSize: 20, color: textColor),
style: TextStyle(fontSize: fontSize, color: textColor),
decoration: InputDecoration(
icon: icon != null ? 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: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/constants.dart';
import 'package:provider/provider.dart';
class AutomationsScreen extends StatefulWidget {
@ -11,7 +16,7 @@ class AutomationsScreen extends StatefulWidget {
class _AutomationsScreenState extends State<AutomationsScreen> {
bool isLoading = true;
//List<Message> messages;
List<AutomationDTO>? allAutomations;
@override
void initState() {
@ -22,47 +27,103 @@ class _AutomationsScreenState extends State<AutomationsScreen> {
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
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(
color: Theme.of(context).primaryColor,
displacement: 20,
onRefresh: () async {
print("TODO refresh");
//await Message.getMessages(this.messages, appContext, true, true);
},
return SingleChildScrollView(
child: Container(
height: size.height * 0.8,
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text("TODO Automations")
],
),
height: size.height * 0.9,
child: FutureBuilder(
future: homieAppContext.clientAPI.automationApi!.automationGetAll(homieAppContext.homeId!),
builder: (context, AsyncSnapshot<List<AutomationDTO>?> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
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_common.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/constants.dart';
import 'package:provider/provider.dart';
@ -86,10 +87,19 @@ class _HomeScreenState extends State<HomeScreen> {
itemBuilder: (BuildContext context, int index) {
return InkWell(
onTap: () {
setState(() {
debugPrint(roomsMaindetails[index].toString());
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => RoomDetailPage(
roomMainDetailDTO: roomsMaindetails[index]
)
),
);
/*setState(() {
//selectedSection = menuDTO.sections[index];
print("Hero to room detail");
});
});*/
},
child: Container(
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/Screens/Debug/DebugPage.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/constants.dart';
import 'package:provider/provider.dart';
@ -62,8 +63,9 @@ class _MainPageState extends State<MainPage> {
HomeScreen(),
SecurityScreen(),
AutomationsScreen(),
DevicesScreen(),
EnergyScreen(),
ProfileScreen(),
//ProfileScreen(),
],
),
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: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/constants.dart';
import 'package:provider/provider.dart';
class SecurityScreen extends StatefulWidget {
@ -11,7 +18,8 @@ class SecurityScreen extends StatefulWidget {
class _SecurityScreenState extends State<SecurityScreen> {
bool isLoading = true;
//List<Message> messages;
List<AlarmModeDTO>? allAlarmModes;
AlarmModeDTO? currentAlarmMode;
@override
void initState() {
@ -22,31 +30,8 @@ class _SecurityScreenState extends State<SecurityScreen> {
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
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(
color: Theme.of(context).primaryColor,
displacement: 20,
@ -55,16 +40,98 @@ class _SecurityScreenState extends State<SecurityScreen> {
//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 Security")
],
),
height: size.height * 0.842,
//child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
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";
case NavItemIcon.automations:
return "Automations";
case NavItemIcon.devices:
return "Devices";
case NavItemIcon.energy:
return "Energy";
case NavItemIcon.profile:

View File

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

View File

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

View File

@ -5,8 +5,12 @@
import FlutterMacOS
import Foundation
import firebase_core
import firebase_messaging
import sqflite
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"))
}

View File

@ -18,6 +18,7 @@ Name | Type | Description | Notes
**createdDate** | [**DateTime**](DateTime.md) | | [optional]
**updatedDate** | [**DateTime**](DateTime.md) | | [optional]
**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 []]
**programmedMode** | [**OneOfProgrammedMode**](OneOfProgrammedMode.md) | | [optional]
**geolocalizedMode** | [**OneOfGeolocalizedMode**](OneOfGeolocalizedMode.md) | | [optional]

View File

@ -9,6 +9,7 @@ import 'package:mycore_api/api.dart';
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**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 []]
**programmedMode** | [**OneOfProgrammedMode**](OneOfProgrammedMode.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 []]
**actions** | [**List<Action>**](Action.md) | | [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)

View File

@ -12,6 +12,7 @@ Name | Type | Description | Notes
**conditions** | [**List<Condition>**](Condition.md) | | [optional] [default to const []]
**actions** | [**List<Action>**](Action.md) | | [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)

View File

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

View File

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

View File

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

View File

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

View File

@ -9,6 +9,14 @@ packages:
url: "https://pub.dev"
source: hosted
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:
dependency: transitive
description:
@ -33,6 +41,14 @@ packages:
url: "https://pub.dev"
source: hosted
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:
dependency: transitive
description:
@ -209,6 +225,54 @@ packages:
url: "https://pub.dev"
source: hosted
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:
dependency: transitive
description:
@ -455,6 +519,14 @@ packages:
url: "https://pub.dev"
source: hosted
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:
dependency: transitive
description:

View File

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

View File

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

View File

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