commit 7b67ff5506320e61611512364daa26428103f172
Author: ajournaux <ajournaux@TLS-GPS-AJOURN.inra.local>
Date:   Mon Jul 8 15:26:56 2024 +0200

    Version 1.2 : Ajout de l'indicateur de connexion

diff --git a/INRAETemplate/INRAETemplate.csproj b/INRAETemplate/INRAETemplate.csproj
index c48ae8e..69961a9 100644
--- a/INRAETemplate/INRAETemplate.csproj
+++ b/INRAETemplate/INRAETemplate.csproj
@@ -32,7 +32,7 @@
 
 	<ItemGroup>
 		<!-- App Icon -->
-		<MauiIcon Include="Resources\AppIcon\ae.svg" Color="#FFFFFF"/>
+		<MauiIcon Include="Resources\AppIcon\ae.svg" Color="#FFFFFF" />
 
 		<!-- Splash Screen -->
 		<MauiSplashScreen Include="Resources\Images\logo_inrae.svg" Color="White" BaseSize="128,128" />
@@ -68,6 +68,9 @@
 	  <MauiXaml Update="View\SettingsView.xaml">
 	    <Generator>MSBuild:Compile</Generator>
 	  </MauiXaml>
+	  <MauiXaml Update="View\Tools\ConnectionIndicatorView.xaml">
+	    <Generator>MSBuild:Compile</Generator>
+	  </MauiXaml>
 	  <MauiXaml Update="View\VivantEditionView.xaml">
 	    <Generator>MSBuild:Compile</Generator>
 	  </MauiXaml>
diff --git a/INRAETemplate/INRAETemplate.csproj.user b/INRAETemplate/INRAETemplate.csproj.user
index 1e9040a..ae85686 100644
--- a/INRAETemplate/INRAETemplate.csproj.user
+++ b/INRAETemplate/INRAETemplate.csproj.user
@@ -3,7 +3,7 @@
   <PropertyGroup>
     <IsFirstTimeProjectOpen>False</IsFirstTimeProjectOpen>
     <ActiveDebugFramework>net7.0-android</ActiveDebugFramework>
-    <ActiveDebugProfile>Samsung SM-G736B (Android 14.0 - API 34)</ActiveDebugProfile>
+    <ActiveDebugProfile>Coppernic C-One (Android 7.1 - API 25)</ActiveDebugProfile>
     <SelectedPlatformGroup>PhysicalDevice</SelectedPlatformGroup>
     <DefaultDevice>pixel_5_-_api_26</DefaultDevice>
   </PropertyGroup>
@@ -17,6 +17,9 @@
     <MauiXaml Update="View\SettingsView.xaml">
       <SubType>Designer</SubType>
     </MauiXaml>
+    <MauiXaml Update="View\Tools\ConnectionIndicatorView.xaml">
+      <SubType>Designer</SubType>
+    </MauiXaml>
     <MauiXaml Update="View\VivantEditionView.xaml">
       <SubType>Designer</SubType>
     </MauiXaml>
diff --git a/INRAETemplate/MauiProgram.cs b/INRAETemplate/MauiProgram.cs
index 4b9ee22..a81130a 100644
--- a/INRAETemplate/MauiProgram.cs
+++ b/INRAETemplate/MauiProgram.cs
@@ -1,4 +1,7 @@
 ﻿using CommunityToolkit.Maui;
+using INRAETemplate.Services;
+using INRAETemplate.View;
+using INRAETemplate.ViewModel;
 using Microsoft.Extensions.Logging;
 
 namespace INRAETemplate;
@@ -20,8 +23,24 @@ public static class MauiProgram
                 fonts.AddFont("fa-solid.ttf", "FASolid");
 			});
 
+        // Services
+        builder.Services.AddSingleton<ConnexionService>();
+
+		// Views
+		builder.Services.AddSingleton<AboutView>();
+		builder.Services.AddSingleton<SettingsView>();
+		builder.Services.AddSingleton<VivantEditionView>();
+		builder.Services.AddSingleton<VivantView>();
+
+        // ViewModels
+		builder.Services.AddSingleton<AboutViewModel>();
+		builder.Services.AddSingleton<SettingsViewModel>();
+		builder.Services.AddSingleton<VivantEditionViewModel>();
+        builder.Services.AddSingleton<VivantViewModel>();
+
+
 #if DEBUG
-		builder.Logging.AddDebug();
+        builder.Logging.AddDebug();
 #endif
 
 		return builder.Build();
diff --git a/INRAETemplate/Platforms/Android/AndroidManifest.xml b/INRAETemplate/Platforms/Android/AndroidManifest.xml
index f59f634..5761271 100644
--- a/INRAETemplate/Platforms/Android/AndroidManifest.xml
+++ b/INRAETemplate/Platforms/Android/AndroidManifest.xml
@@ -1,7 +1,6 @@
 ﻿<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="120" android:versionName="1.2.0">
 	<application android:allowBackup="true" android:supportsRtl="true" android:icon="@mipmap/ae"></application>
 	<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
 	<uses-permission android:name="android.permission.INTERNET" />
-	<uses-sdk android:minSdkVersion="24" android:targetSdkVersion="34" />
 </manifest>
\ No newline at end of file
diff --git a/INRAETemplate/Services/ConnexionService.cs b/INRAETemplate/Services/ConnexionService.cs
new file mode 100644
index 0000000..a99c76e
--- /dev/null
+++ b/INRAETemplate/Services/ConnexionService.cs
@@ -0,0 +1,75 @@
+﻿using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Net.NetworkInformation;
+using System.Runtime.CompilerServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace INRAETemplate.Services
+{
+    public class ConnexionService : INotifyPropertyChanged
+    {
+        private bool isINRAE;
+        public bool IsINRAE
+        {
+            get => isINRAE;
+            set => SetProperty(ref isINRAE, value);
+        }
+
+        // e est null à l'init
+        public async Task SetIsConnected(ConnectivityChangedEventArgs e = null)
+        {
+            bool internetAccess = e is null ? Connectivity.NetworkAccess == NetworkAccess.Internet : e.NetworkAccess == NetworkAccess.Internet;
+            // Test de l'accès au serveur
+            try
+            {
+                await Task.Run(() =>
+                {
+                    IsINRAE = new Ping().Send("138.102.166.28").Status == IPStatus.Success || new Ping().Send("147.100.200.52").Status == IPStatus.Success;
+                });
+                IsINRAE = internetAccess && IsINRAE;
+            }
+            catch (Exception)
+            {
+                IsINRAE = false;
+            }
+        }
+
+        public ConnexionService()
+        {
+            Connectivity.ConnectivityChanged += Connectivity_ConnectivityChanged;
+            Task.Run(() => this.SetIsConnected()).Wait();
+            // ou : new Action(async () => await SetIsConnected())();
+        }
+
+        ~ConnexionService()
+        {
+            Connectivity.ConnectivityChanged -= Connectivity_ConnectivityChanged;
+        }
+
+        public void Connectivity_ConnectivityChanged(object sender, ConnectivityChangedEventArgs e)
+        {
+            Task.Run(() => this.SetIsConnected(e)).Wait();
+        }
+
+        #region INPC
+        public event PropertyChangedEventHandler PropertyChanged;
+
+        protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyname = null)
+        {
+            if (Equals(storage, value)) return false;
+
+            storage = value;
+            OnPropertyChanged(propertyname);
+            return true;
+        }
+
+        private void OnPropertyChanged([CallerMemberName] string propertyName = null)
+        {
+            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+        }
+        #endregion
+    }
+}
diff --git a/INRAETemplate/View/AboutView.xaml b/INRAETemplate/View/AboutView.xaml
index 2fd5c1d..eeb15eb 100644
--- a/INRAETemplate/View/AboutView.xaml
+++ b/INRAETemplate/View/AboutView.xaml
@@ -2,8 +2,10 @@
 <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
              xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
              x:Class="INRAETemplate.View.AboutView"
+             xmlns:tools="clr-namespace:INRAETemplate.View.Tools"
              Title="About">
     <StackLayout BackgroundColor="{StaticResource InraePrimary}" Spacing="0">
+        <tools:ConnectionIndicatorView />
         <ScrollView>
             <StackLayout Spacing="0">
                 <StackLayout
@@ -16,11 +18,23 @@
                         <StackLayout>
                             <Frame BorderColor="{StaticResource InraePrimary}" Margin="0,0,0,20">
                                 <Label 
-                                        Text="About..."
+                                        Text="A propos"
                                         VerticalOptions="Center" 
                                         HorizontalOptions="Center"
                                         Style="{StaticResource textTitre}"/>
                             </Frame>
+                            <Grid ColumnDefinitions="70*,30*" RowDefinitions="auto">
+                                <Label
+                                    Grid.Row="0"
+                                    Grid.Column="0"
+                                    Text="Version Templace :"
+                                    Style="{StaticResource textLabel}"/>
+                                <Label
+                                    Grid.Row="0"
+                                    Grid.Column="1"
+                                    Text="{Binding VersionTemplate}"
+                                    Style="{StaticResource textLabel}"/>
+                            </Grid>
                         </StackLayout>
                     </Frame>
                 </StackLayout>
diff --git a/INRAETemplate/View/AboutView.xaml.cs b/INRAETemplate/View/AboutView.xaml.cs
index fb84285..456c63d 100644
--- a/INRAETemplate/View/AboutView.xaml.cs
+++ b/INRAETemplate/View/AboutView.xaml.cs
@@ -1,3 +1,5 @@
+using INRAETemplate.ViewModel;
+
 namespace INRAETemplate.View;
 
 public partial class AboutView : ContentPage
@@ -5,5 +7,6 @@ public partial class AboutView : ContentPage
 	public AboutView()
 	{
 		InitializeComponent();
-	}
+		this.BindingContext = new AboutViewModel();
+    }
 }
\ No newline at end of file
diff --git a/INRAETemplate/View/SettingsView.xaml b/INRAETemplate/View/SettingsView.xaml
index b31d498..64d33af 100644
--- a/INRAETemplate/View/SettingsView.xaml
+++ b/INRAETemplate/View/SettingsView.xaml
@@ -2,9 +2,11 @@
 <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
              xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
              x:Class="INRAETemplate.View.SettingsView"
+             xmlns:tools="clr-namespace:INRAETemplate.View.Tools"
              Title="Settings">
 
     <StackLayout BackgroundColor="{StaticResource InraePrimary}" Spacing="0">
+        <tools:ConnectionIndicatorView />
         <ScrollView>
             <StackLayout Spacing="0">
                 <StackLayout
diff --git a/INRAETemplate/View/Tools/ConnectionIndicatorView.xaml b/INRAETemplate/View/Tools/ConnectionIndicatorView.xaml
new file mode 100644
index 0000000..6d87fea
--- /dev/null
+++ b/INRAETemplate/View/Tools/ConnectionIndicatorView.xaml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<StackLayout
+    x:Class="INRAETemplate.View.Tools.ConnectionIndicatorView"
+    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
+    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+    xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
+    xmlns:vm="clr-namespace:INRAETemplate.Services"
+    x:DataType="vm:ConnexionService">
+
+    <StackLayout.Resources>
+        <ResourceDictionary>
+            <toolkit:InvertedBoolConverter x:Key="NOTConverter" />
+        </ResourceDictionary>
+    </StackLayout.Resources>
+
+    <StackLayout>
+        <!--  connecté  -->
+        <StackLayout
+            BackgroundColor="Green"
+            HorizontalOptions="FillAndExpand"
+            IsVisible="{Binding IsINRAE}">
+            <Label
+                FontAttributes="Bold"
+                FontSize="Small"
+                HorizontalOptions="Center"
+                Text="Connecté"
+                TextColor="White" />
+        </StackLayout>
+
+        <!--  non connecté  -->
+        <StackLayout
+            BackgroundColor="Black"
+            HorizontalOptions="FillAndExpand"
+            IsVisible="{Binding IsINRAE, Converter={StaticResource NOTConverter}}">
+            <Label
+                FontAttributes="Bold"
+                FontSize="Small"
+                HorizontalOptions="Center"
+                Text="Non connecté"
+                TextColor="White" />
+        </StackLayout>
+
+    </StackLayout>
+</StackLayout>
diff --git a/INRAETemplate/View/Tools/ConnectionIndicatorView.xaml.cs b/INRAETemplate/View/Tools/ConnectionIndicatorView.xaml.cs
new file mode 100644
index 0000000..3ad6f68
--- /dev/null
+++ b/INRAETemplate/View/Tools/ConnectionIndicatorView.xaml.cs
@@ -0,0 +1,13 @@
+using INRAETemplate.Services;
+
+namespace INRAETemplate.View.Tools;
+
+public partial class ConnectionIndicatorView : StackLayout
+{
+    public ConnectionIndicatorView()
+    {
+        InitializeComponent();
+        ConnexionService connexionStatus = App.Current.Handler.MauiContext.Services.GetService<ConnexionService>();
+        BindingContext = connexionStatus;
+    }
+}
\ No newline at end of file
diff --git a/INRAETemplate/View/VivantEditionView.xaml b/INRAETemplate/View/VivantEditionView.xaml
index df9ab02..d62bfda 100644
--- a/INRAETemplate/View/VivantEditionView.xaml
+++ b/INRAETemplate/View/VivantEditionView.xaml
@@ -2,9 +2,11 @@
 <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
              xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
              x:Class="INRAETemplate.View.VivantEditionView"
+             xmlns:tools="clr-namespace:INRAETemplate.View.Tools"
              Title="Edition Vivant">
     <Grid>
         <StackLayout BackgroundColor="{StaticResource InraePrimary}" Spacing="0">
+            <tools:ConnectionIndicatorView />
             <ScrollView>
                 <StackLayout Spacing="0">
                     <StackLayout
diff --git a/INRAETemplate/View/VivantView.xaml b/INRAETemplate/View/VivantView.xaml
index 8d90e48..4420d29 100644
--- a/INRAETemplate/View/VivantView.xaml
+++ b/INRAETemplate/View/VivantView.xaml
@@ -2,9 +2,11 @@
 <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
              xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
              x:Class="INRAETemplate.View.VivantView"
+             xmlns:tools="clr-namespace:INRAETemplate.View.Tools"
              Title="Formulaire Vivant">
     <Grid>
         <StackLayout BackgroundColor="{StaticResource InraePrimary}" Spacing="0">
+            <tools:ConnectionIndicatorView />
             <ScrollView>
                 <StackLayout Spacing="0">
                     <StackLayout
@@ -27,7 +29,7 @@
                                         ItemsSource="{Binding Vivants}"
                                         SelectedItem="{Binding VivantSelectionne}"
                                         ItemDisplayBinding="{Binding VivantNom}"/>
-                                <Grid ColumnDefinitions="20*,80*" RowDefinitions="auto,auto">
+                                <Grid ColumnDefinitions="25*,75*" RowDefinitions="auto,auto">
                                     <Label Grid.Column="0"
                                            Grid.Row="0"
                                            Text="Id : "
diff --git a/INRAETemplate/View/VivantView.xaml.cs b/INRAETemplate/View/VivantView.xaml.cs
index d54f90d..8450341 100644
--- a/INRAETemplate/View/VivantView.xaml.cs
+++ b/INRAETemplate/View/VivantView.xaml.cs
@@ -4,9 +4,9 @@ namespace INRAETemplate.View;
 [XamlCompilation(XamlCompilationOptions.Skip)]
 public partial class VivantView : ContentPage
 {
-	public VivantView()
-	{
-		InitializeComponent();
-		this.BindingContext = new VivantViewModel();
-	}
+    public VivantView(VivantViewModel vm)
+    {
+        InitializeComponent();
+        this.BindingContext = vm;
+    }
 }
\ No newline at end of file
diff --git a/INRAETemplate/ViewModel/AboutViewModel.cs b/INRAETemplate/ViewModel/AboutViewModel.cs
new file mode 100644
index 0000000..97c0680
--- /dev/null
+++ b/INRAETemplate/ViewModel/AboutViewModel.cs
@@ -0,0 +1,42 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using INRAETemplate.ViewModel.Base;
+
+namespace INRAETemplate.ViewModel
+{
+    public class AboutViewModel : BaseViewModel
+    {
+        #region Attributs
+        private string versionTemplate;
+
+        #endregion
+
+        #region Propriétés
+
+        public string VersionTemplate
+        {
+            get { return versionTemplate; }
+            set
+            {
+                if (versionTemplate != value)
+                {
+                    versionTemplate = value;
+                    OnPropertyChanged(nameof(VersionTemplate));
+                }
+            }
+        }
+
+        #endregion
+
+        #region Constructeurs
+        public AboutViewModel()
+        {
+            VersionTemplate = AppInfo.Current.VersionString;
+        }
+        #endregion
+    }
+}
diff --git a/INRAETemplate/ViewModel/SettingsViewModel.cs b/INRAETemplate/ViewModel/SettingsViewModel.cs
new file mode 100644
index 0000000..bec0f88
--- /dev/null
+++ b/INRAETemplate/ViewModel/SettingsViewModel.cs
@@ -0,0 +1,12 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace INRAETemplate.ViewModel
+{
+    public class SettingsViewModel
+    {
+    }
+}
diff --git a/INRAETemplate/ViewModel/VivantViewModel.cs b/INRAETemplate/ViewModel/VivantViewModel.cs
index fb1561b..5e75b63 100644
--- a/INRAETemplate/ViewModel/VivantViewModel.cs
+++ b/INRAETemplate/ViewModel/VivantViewModel.cs
@@ -1,5 +1,6 @@
 ﻿using INRAETemplate.DAO;
 using INRAETemplate.Model;
+using INRAETemplate.Services;
 using INRAETemplate.View;
 using INRAETemplate.ViewModel.Base;
 using System;
@@ -14,6 +15,12 @@ namespace INRAETemplate.ViewModel
 {
     public class VivantViewModel : BaseViewModel
     {
+        #region Services
+
+        private readonly ConnexionService connService;
+
+        #endregion
+
         #region Attributs
         private int vivantId;
         private string vivantNom;
@@ -83,12 +90,15 @@ namespace INRAETemplate.ViewModel
         #endregion
 
         #region Constructeurs
-        public VivantViewModel()
+
+        public VivantViewModel(ConnexionService connService)
         {
+            this.connService = connService;
             //Alimentation du Picker à partir de VivantDAO
             Vivants = new ObservableCollection<Vivant>(VivantDAO.GetVivants());
             EditionCommand = new Command(async () => await Edition());
         }
+
         #endregion
 
         #region Méthodes
