Refactor code structure for improved readability and maintainability
20
DaireApplication/App.axaml
Normal file
@@ -0,0 +1,20 @@
|
||||
<Application xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:Class="DaireApplication.App"
|
||||
xmlns:local="using:DaireApplication"
|
||||
RequestedThemeVariant="Default">
|
||||
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
|
||||
|
||||
<Application.DataTemplates>
|
||||
<local:ViewLocator/>
|
||||
|
||||
</Application.DataTemplates>
|
||||
|
||||
|
||||
|
||||
<Application.Styles>
|
||||
<FluentTheme />
|
||||
|
||||
</Application.Styles>
|
||||
|
||||
</Application>
|
||||
32
DaireApplication/App.axaml.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using DaireApplication.ViewModels;
|
||||
using DaireApplication.Views;
|
||||
|
||||
namespace DaireApplication
|
||||
{
|
||||
public partial class App : Application
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
public override void OnFrameworkInitializationCompleted()
|
||||
{
|
||||
// Migrate CSV files by adding missing columns with default values
|
||||
DataBase.DataPathManager.MigrateCsvFiles();
|
||||
|
||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
desktop.MainWindow = new MainWindow
|
||||
{
|
||||
DataContext = new MainWindowViewModel(),
|
||||
};
|
||||
}
|
||||
|
||||
base.OnFrameworkInitializationCompleted();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
BIN
DaireApplication/Assets/AdminGraph.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
DaireApplication/Assets/AdminMachine.png
Normal file
|
After Width: | Height: | Size: 56 KiB |
BIN
DaireApplication/Assets/Board.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
DaireApplication/Assets/Fonts/HLL.ttf
Normal file
BIN
DaireApplication/Assets/Fonts/Helvetica.ttf
Normal file
BIN
DaireApplication/Assets/Home.png
Normal file
|
After Width: | Height: | Size: 416 B |
BIN
DaireApplication/Assets/LeftArrow.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
DaireApplication/Assets/LineDots.png
Normal file
|
After Width: | Height: | Size: 249 B |
BIN
DaireApplication/Assets/Logo.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
DaireApplication/Assets/Machine.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
DaireApplication/Assets/Manual.png
Normal file
|
After Width: | Height: | Size: 372 B |
BIN
DaireApplication/Assets/ManualControlMachine.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
DaireApplication/Assets/Plus.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
DaireApplication/Assets/RedUpArrow.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
DaireApplication/Assets/RightArrow.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
DaireApplication/Assets/Settings.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
DaireApplication/Assets/TempArrow.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
DaireApplication/Assets/TemperingGraphics.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
DaireApplication/Assets/TemperingMachine.png
Normal file
|
After Width: | Height: | Size: 67 KiB |
BIN
DaireApplication/Assets/UpArrow.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
DaireApplication/Assets/avalonia-logo.ico
Normal file
|
After Width: | Height: | Size: 172 KiB |
BIN
DaireApplication/Assets/bluePlug.png
Normal file
|
After Width: | Height: | Size: 9.8 KiB |
BIN
DaireApplication/Assets/errorIcon.png
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
DaireApplication/Assets/greenPlug.png
Normal file
|
After Width: | Height: | Size: 9.8 KiB |
BIN
DaireApplication/Assets/homeTrack.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
DaireApplication/Assets/icons8-green-circle-48.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
DaireApplication/Assets/icons8-red-circle-48.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
DaireApplication/Assets/orangePlug.png
Normal file
|
After Width: | Height: | Size: 9.8 KiB |
BIN
DaireApplication/Assets/purplePlug.png
Normal file
|
After Width: | Height: | Size: 9.9 KiB |
BIN
DaireApplication/Assets/redPlug.png
Normal file
|
After Width: | Height: | Size: 9.8 KiB |
BIN
DaireApplication/Assets/warningIcon.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
DaireApplication/Assets/wifi.png
Normal file
|
After Width: | Height: | Size: 6.0 KiB |
BIN
DaireApplication/Assets/wifioff.png
Normal file
|
After Width: | Height: | Size: 6.9 KiB |
BIN
DaireApplication/Assets/yellowPlug.png
Normal file
|
After Width: | Height: | Size: 9.9 KiB |
294
DaireApplication/Automatic_Fountain_Control_Implementation.md
Normal file
@@ -0,0 +1,294 @@
|
||||
# Automatic Fountain Control Implementation
|
||||
|
||||
## Overview
|
||||
|
||||
This implementation adds automatic fountain control functionality that triggers after the pouring phase completes when the pedal is in Auto mode. The fountain state is determined by the second control box (RecipeTable.Fountain property).
|
||||
|
||||
## ✅ Expected Behavior
|
||||
|
||||
- **After pouring phase completion** and **pedal mode set to Auto**:
|
||||
- If the second control box is **checked/enabled** → Fountain should **open**
|
||||
- If the second control box is **unchecked/disabled** → Fountain should **remain closed**
|
||||
- **No blinking/flashing** of the Chocolate button after automatic control is established
|
||||
|
||||
## 🔧 Implementation Details
|
||||
|
||||
### 1. New Properties Added
|
||||
|
||||
```csharp
|
||||
public bool isAutomaticFountainControlActive { get; set; } = false;
|
||||
```
|
||||
|
||||
This flag prevents interference between automatic fountain control and normal temperature-based fountain control.
|
||||
|
||||
### 2. New Methods Added
|
||||
|
||||
#### `HandleAutomaticFountainControlAfterPouring(Settings settings)`
|
||||
- **Purpose**: Main orchestrator for automatic fountain control
|
||||
- **Trigger**: Called when pouring phase completes
|
||||
- **Logic**:
|
||||
- Checks if pedal is in Auto mode (`!settings._recipeTable.Pedal.Value`)
|
||||
- Reads second control box state (`settings._recipeTable.Fountain.Value`)
|
||||
- Calls appropriate fountain control method
|
||||
|
||||
#### `TurnOnFountainAutomatically()`
|
||||
- **Purpose**: Automatically turns ON the fountain motor
|
||||
- **Actions**:
|
||||
- Sets fountain motor state variables
|
||||
- **Sends hardware command** to turn ON fountain motor
|
||||
- Updates UI to show fountain is ON
|
||||
- Logs the action for debugging
|
||||
|
||||
#### `TurnOffFountainAutomatically()`
|
||||
- **Purpose**: Automatically turns OFF the fountain motor
|
||||
- **Actions**:
|
||||
- Sets fountain motor state variables
|
||||
- **Sends hardware command** to turn OFF fountain motor
|
||||
- Updates UI to show fountain is OFF
|
||||
- Logs the action for debugging
|
||||
|
||||
#### `ResetAutomaticFountainControl()`
|
||||
- **Purpose**: Resets the automatic control flag
|
||||
- **Usage**: Called when manual control is needed or recipe is reset
|
||||
|
||||
### 3. Integration Points
|
||||
|
||||
#### Pouring Phase Completion
|
||||
Modified `PouringTimer` method to call automatic fountain control:
|
||||
|
||||
```csharp
|
||||
// Handle automatic fountain control after pouring phase completion
|
||||
await HandleAutomaticFountainControlAfterPouring(result);
|
||||
```
|
||||
|
||||
#### Fountain Control Logic Protection
|
||||
Modified main fountain control logic to respect automatic control:
|
||||
|
||||
```csharp
|
||||
//Fountain Motor - Normal temperature-based control
|
||||
if (checkFountainTMT_PMT && !isAutomaticFountainControlActive)
|
||||
{
|
||||
// Normal temperature-based fountain control
|
||||
}
|
||||
|
||||
//Fountain Motor - Manual control (when not in automatic mode)
|
||||
if (!checkFountainTMT_PMT && !isAutomaticFountainControlActive)
|
||||
{
|
||||
// Manual fountain control
|
||||
}
|
||||
```
|
||||
|
||||
#### Automatic Fountain Control Processing
|
||||
Added dedicated section for automatic fountain control in main monitoring loop:
|
||||
|
||||
```csharp
|
||||
//Fountain Motor - Automatic control (when automatic control is active)
|
||||
if (isAutomaticFountainControlActive)
|
||||
{
|
||||
// Handle automatic fountain control state changes
|
||||
if (startFountainMotorFlashing == 0 && sendComFountainMotor == 1 && errors.Count == 0 && !isPaused)
|
||||
{
|
||||
// Turn ON fountain motor
|
||||
// Send hardware command
|
||||
// Update UI
|
||||
}
|
||||
else if (startFountainMotorFlashing == 1 && sendComFountainMotor == 0)
|
||||
{
|
||||
// Turn OFF fountain motor
|
||||
// Send hardware command
|
||||
// Update UI
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Manual Override
|
||||
Modified `FountainClick` method to reset automatic control when user manually controls fountain:
|
||||
|
||||
```csharp
|
||||
// Reset automatic fountain control flag when user manually controls fountain
|
||||
if (isAutomaticFountainControlActive)
|
||||
{
|
||||
ResetAutomaticFountainControl();
|
||||
}
|
||||
```
|
||||
|
||||
#### Recipe Lifecycle Management
|
||||
- **Recipe Start**: Resets automatic control flag
|
||||
- **Recipe Stop**: Resets automatic control flag
|
||||
|
||||
## 🔄 Control Flow
|
||||
|
||||
1. **Recipe Execution**: Normal recipe phases (heating → cooling → pouring)
|
||||
2. **Pouring Phase Completion**:
|
||||
- Recipe timer completes
|
||||
- Pedal control is set based on recipe settings
|
||||
- **NEW**: Automatic fountain control is triggered
|
||||
3. **Automatic Fountain Control**:
|
||||
- Checks pedal mode (must be Auto)
|
||||
- Checks second control box state
|
||||
- Sets fountain state accordingly
|
||||
- **Sends hardware commands** to control fountain motor
|
||||
- Sets flag to prevent interference
|
||||
4. **Hardware Control**: Main monitoring loop processes automatic control commands
|
||||
5. **Manual Override**: User can manually control fountain, which resets automatic control
|
||||
|
||||
## 🛡️ Safety Features
|
||||
|
||||
1. **Flag Protection**: Automatic control flag prevents conflicts with normal fountain control
|
||||
2. **Manual Override**: Users can always take manual control
|
||||
3. **Recipe Reset**: Automatic control is reset when starting/stopping recipes
|
||||
4. **Error Handling**: Comprehensive try-catch blocks with logging
|
||||
5. **UI Updates**: Visual feedback shows fountain state changes
|
||||
6. **Hardware Commands**: Direct hardware control ensures fountain state changes are executed
|
||||
|
||||
## 🚫 Blinking Prevention
|
||||
|
||||
### Issue Fixed
|
||||
The "Chocolate" button was blinking/toggling after pouring phase completion due to conflicting fountain control mechanisms.
|
||||
|
||||
### Solution Implemented
|
||||
|
||||
#### 1. **Flashing Flag Protection**
|
||||
Modified automatic fountain control to set `startFountainMotorFlashing = -1` instead of `1`:
|
||||
|
||||
```csharp
|
||||
// In TurnOffFountainAutomatically()
|
||||
startFountainMotorFlashing = -1; // Prevent flashing in automatic mode
|
||||
```
|
||||
|
||||
#### 2. **InteractiveUILoop Protection**
|
||||
Added automatic control check to prevent flashing in UI loop:
|
||||
|
||||
```csharp
|
||||
// In InteractiveUILoop.cs
|
||||
if (_mainWindow.startFountainMotorFlashing == 1 && !_mainWindow.isAutomaticFountainControlActive)
|
||||
{
|
||||
// Only flash when not in automatic control mode
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. **Temperature-Based Control Protection**
|
||||
Added automatic control checks to prevent normal fountain control from interfering:
|
||||
|
||||
```csharp
|
||||
// Prevent normal fountain control from setting flashing when automatic control is active
|
||||
if (!isAutomaticFountainControlActive)
|
||||
{
|
||||
startFountainMotorFlashing = 1;
|
||||
}
|
||||
```
|
||||
|
||||
#### 4. **Flashing Processing Protection**
|
||||
Added automatic control check to flashing processing logic:
|
||||
|
||||
```csharp
|
||||
if (startFountainMotorFlashing == 1 && !isAutomaticFountainControlActive)
|
||||
{
|
||||
// Only process flashing when not in automatic control mode
|
||||
}
|
||||
```
|
||||
|
||||
### Result
|
||||
- **No more blinking** of the Chocolate button after automatic control is established
|
||||
- **Steady state** maintained based on second control box value
|
||||
- **Clean visual feedback** without distracting flashing animations
|
||||
|
||||
## 📝 Debugging
|
||||
|
||||
The implementation includes debug logging for:
|
||||
- Automatic fountain control activation
|
||||
- Fountain state changes (ON/OFF)
|
||||
- Hardware command execution
|
||||
- Flag resets
|
||||
- Error conditions
|
||||
|
||||
## 🧪 Testing Scenarios
|
||||
|
||||
### Scenario 1: Second Box Checked, Auto Mode
|
||||
1. Start recipe with second control box enabled
|
||||
2. Complete pouring phase
|
||||
3. **Expected**: Fountain turns ON automatically and chocolate flows (no blinking)
|
||||
|
||||
### Scenario 2: Second Box Unchecked, Auto Mode
|
||||
1. Start recipe with second control box disabled
|
||||
2. Complete pouring phase
|
||||
3. **Expected**: Fountain remains OFF and chocolate flow stops (no blinking)
|
||||
|
||||
### Scenario 3: Manual Mode
|
||||
1. Start recipe in manual pedal mode
|
||||
2. Complete pouring phase
|
||||
3. **Expected**: No automatic fountain control (manual control only)
|
||||
|
||||
### Scenario 4: Manual Override
|
||||
1. Complete recipe with automatic fountain control active
|
||||
2. Manually click fountain button
|
||||
3. **Expected**: Automatic control is reset, manual control takes over
|
||||
|
||||
### Scenario 5: No Blinking Verification
|
||||
1. Complete recipe with automatic fountain control
|
||||
2. **Expected**: Chocolate button remains steady (ON or OFF) without blinking
|
||||
|
||||
## 🔧 Configuration
|
||||
|
||||
The second control box is configured through the `RecipeTable.Fountain` property:
|
||||
- `true` = Fountain should be ON after pouring
|
||||
- `false` = Fountain should be OFF after pouring
|
||||
|
||||
## 🔧 Key Fixes Applied
|
||||
|
||||
### Issue: Fountain State Not Changing
|
||||
**Problem**: Automatic control was setting state variables but not sending hardware commands.
|
||||
|
||||
**Solution**:
|
||||
1. **Direct Hardware Control**: Modified `TurnOnFountainAutomatically()` and `TurnOffFountainAutomatically()` to send actual hardware commands
|
||||
2. **Dedicated Processing**: Added automatic fountain control section in main monitoring loop
|
||||
3. **State Synchronization**: Ensured UI updates and hardware commands are synchronized
|
||||
|
||||
### Issue: Chocolate Button Blinking
|
||||
**Problem**: The Chocolate button was blinking/toggling after pouring phase completion.
|
||||
|
||||
**Solution**:
|
||||
1. **Flashing Flag Control**: Set `startFountainMotorFlashing = -1` in automatic control to prevent flashing
|
||||
2. **UI Loop Protection**: Added automatic control check to InteractiveUILoop
|
||||
3. **Temperature Control Protection**: Prevented normal fountain control from interfering
|
||||
4. **Flashing Processing Protection**: Added automatic control check to flashing processing logic
|
||||
|
||||
### Hardware Command Implementation
|
||||
```csharp
|
||||
// Turn ON fountain motor
|
||||
var fount = _mapping.Find(x => x.Name.ToLower() == "Helix".ToLower());
|
||||
if (fount != null && fount.BitNumbers.Count > 0)
|
||||
{
|
||||
foreach (var bit in fount.BitNumbers)
|
||||
{
|
||||
holdingRegister.motor |= (ushort)(1 << bit);
|
||||
}
|
||||
await WriteToSerialAsync("Automatic Fountain On");
|
||||
}
|
||||
|
||||
// Turn OFF fountain motor
|
||||
var fount = _mapping.Find(x => x.Name.ToLower() == "Helix".ToLower());
|
||||
if (fount != null && fount.BitNumbers.Count > 0)
|
||||
{
|
||||
foreach (var bit in fount.BitNumbers)
|
||||
{
|
||||
holdingRegister.motor &= (ushort)~(1 << bit);
|
||||
}
|
||||
await WriteToSerialAsync("Automatic Fountain Off");
|
||||
}
|
||||
```
|
||||
|
||||
## 📋 Requirements Met
|
||||
|
||||
✅ **Automatic triggering** after pouring phase completion
|
||||
✅ **Pedal mode detection** (Auto mode only)
|
||||
✅ **Second control box integration** (RecipeTable.Fountain)
|
||||
✅ **Dynamic fountain control** (open/close based on box state)
|
||||
✅ **Hardware command execution** (actual fountain motor control)
|
||||
✅ **No interference** with existing fountain control logic
|
||||
✅ **Manual override capability**
|
||||
✅ **Proper error handling and logging**
|
||||
✅ **UI feedback** for fountain state changes
|
||||
✅ **Chocolate flow control** (stops/starts based on fountain state)
|
||||
✅ **No blinking/flashing** of Chocolate button after automatic control
|
||||
✅ **Steady state maintenance** based on second control box value
|
||||
75
DaireApplication/DaireApplication.csproj
Normal file
@@ -0,0 +1,75 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Models\" />
|
||||
<AvaloniaResource Include="Assets\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AvaloniaResource Include="Assets/Fonts/Helvetica.ttf" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Assets\AdminGraph.png" />
|
||||
<None Remove="Assets\AdminMachine.png" />
|
||||
<None Remove="Assets\bluePlug.png" />
|
||||
<None Remove="Assets\errorIcon.png" />
|
||||
<None Remove="Assets\Fonts\Helvetica.ttf" />
|
||||
<None Remove="Assets\greenPlug.png" />
|
||||
<None Remove="Assets\Home.png" />
|
||||
<None Remove="Assets\homeTrack.png" />
|
||||
<None Remove="Assets\icons8-green-circle-48.png" />
|
||||
<None Remove="Assets\icons8-red-circle-48.png" />
|
||||
<None Remove="Assets\LeftArrow.png" />
|
||||
<None Remove="Assets\LineDots.png" />
|
||||
<None Remove="Assets\Logo.png" />
|
||||
<None Remove="Assets\Machine.png" />
|
||||
<None Remove="Assets\Manual.png" />
|
||||
<None Remove="Assets\orangePlug.png" />
|
||||
<None Remove="Assets\Plus.png" />
|
||||
<None Remove="Assets\purplePlug.png" />
|
||||
<None Remove="Assets\redPlug.png" />
|
||||
<None Remove="Assets\Settings.png" />
|
||||
<None Remove="Assets\TemperingGraphics.png" />
|
||||
<None Remove="Assets\TemperingMachine.png" />
|
||||
<None Remove="Assets\UpArrow.png" />
|
||||
<None Remove="Assets\warningIcon.png" />
|
||||
<None Remove="Assets\wifi.png" />
|
||||
<None Remove="Assets\wifioff.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia" Version="11.2.1" />
|
||||
<PackageReference Include="Avalonia.Desktop" Version="11.2.1" />
|
||||
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.2.1" />
|
||||
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.2.1" />
|
||||
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
||||
<PackageReference Include="Avalonia.Diagnostics" Version="11.2.1">
|
||||
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
|
||||
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Avalonia.ReactiveUI" Version="11.2.1" />
|
||||
<PackageReference Include="System.IO.Ports" Version="9.0.2" />
|
||||
<PackageReference Include="System.Management" Version="9.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<UpToDateCheckInput Remove="Views\UserController\Settings.axaml" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<UpToDateCheckInput Remove="Views\UserController\RecipeEdit.axaml" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<UpToDateCheckInput Remove="Views\UserController\Admin.axaml" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
202
DaireApplication/DataBase/ConfigrationTable.cs
Normal file
@@ -0,0 +1,202 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace DaireApplication.DataBase;
|
||||
|
||||
public class ConfigrationTable
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public int Max { get; set; } = 0;
|
||||
public int Min { get; set; } = 0;
|
||||
public List<int> H_out { get; set; } = new();
|
||||
public List<int> FC_out { get; set; } = new();
|
||||
public List<int> SC_out { get; set; } = new();
|
||||
public int kp { get; set; } = 0;
|
||||
public int ki { get; set; } = 0;
|
||||
public int kd { get; set; } = 0;
|
||||
public int kl { get; set; } = 0;
|
||||
public string name { get; set; } = "";
|
||||
public float i_neut { get; set; } = 0;
|
||||
public float i_mot1 { get; set; } = 0;
|
||||
public float i_mot2 { get; set; } = 0;
|
||||
public float FC_Threshold { get; set; } = 3;
|
||||
public float HeatConRange { get; set; } = 50;
|
||||
|
||||
public List<ConfigrationTable> ReadConfigrations()
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("Configration.csv");
|
||||
List<ConfigrationTable> configrations = new List<ConfigrationTable>();
|
||||
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
using StreamReader reader = new(filePath);
|
||||
string header = reader.ReadLine();
|
||||
while (!reader.EndOfStream)
|
||||
{
|
||||
string[] columns = reader.ReadLine().Split(',');
|
||||
configrations.Add(new ConfigrationTable
|
||||
{
|
||||
Id = int.Parse(columns[0]),
|
||||
Max = int.Parse(columns[1]),
|
||||
Min = int.Parse(columns[2]),
|
||||
H_out = columns[3].Split('|', StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToList(),
|
||||
FC_out = columns[4].Split('|', StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToList(),
|
||||
SC_out = columns[5].Split('|', StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToList(),
|
||||
kp = int.Parse(columns[6]),
|
||||
ki = int.Parse(columns[7]),
|
||||
kd = int.Parse(columns[8]),
|
||||
kl = int.Parse(columns[9]),
|
||||
name=columns[10],
|
||||
i_neut= float.Parse(columns[11]),
|
||||
i_mot1= float.Parse(columns[12]),
|
||||
i_mot2= float.Parse(columns[13]),
|
||||
FC_Threshold = float.Parse(columns[14]),
|
||||
HeatConRange = float.Parse(columns[15]),
|
||||
});
|
||||
}
|
||||
return configrations;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int GetMaxId()
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("Configration.csv");
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
return File.ReadAllLines(filePath)
|
||||
.Select(line => line.Split(','))
|
||||
.Where(columns => columns.Length > 0)
|
||||
.Select(columns => int.TryParse(columns[0], out int id) ? id : 0)
|
||||
.Max();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public ConfigrationTable ReadConfigrationById(string id)
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("Configration.csv");
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
foreach (var line in File.ReadLines(filePath))
|
||||
{
|
||||
string[] columns = line.Split(',');
|
||||
if (columns[0] == id)
|
||||
{
|
||||
return new ConfigrationTable
|
||||
{
|
||||
Id = int.Parse(columns[0]),
|
||||
Max = int.Parse(columns[1]),
|
||||
Min = int.Parse(columns[2]),
|
||||
H_out = columns[3].Split('|', StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToList(),
|
||||
FC_out = columns[4].Split('|', StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToList(),
|
||||
SC_out = columns[5].Split('|', StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToList(),
|
||||
kp = int.Parse(columns[6]),
|
||||
ki = int.Parse(columns[7]),
|
||||
kd = int.Parse(columns[8]),
|
||||
kl = int.Parse(columns[9]),
|
||||
name=columns[10],
|
||||
i_neut = float.Parse(columns[11]),
|
||||
i_mot1 = float.Parse(columns[12]),
|
||||
i_mot2 = float.Parse(columns[13]),
|
||||
FC_Threshold = float.Parse(columns[14]),
|
||||
HeatConRange = float.Parse(columns[15]),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool AddConfigration(ConfigrationTable data)
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("Configration.csv");
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
string newEntry = string.Join(",", [
|
||||
GetMaxId() + 1,
|
||||
data.Max,
|
||||
data.Min,
|
||||
string.Join("|", data.H_out),
|
||||
string.Join("|", data.FC_out),
|
||||
string.Join("|", data.SC_out),
|
||||
data.kp,
|
||||
data.ki,
|
||||
data.kd,
|
||||
data.kl,
|
||||
data.name,
|
||||
data.i_neut,
|
||||
data.i_mot1,
|
||||
data.i_mot2,
|
||||
data.FC_Threshold,
|
||||
data.HeatConRange
|
||||
]);
|
||||
File.AppendAllText(filePath, newEntry + Environment.NewLine);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool DeleteConfigration(string id)
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("Configration.csv");
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
var filteredLines = File.ReadLines(filePath).Where(line => !line.StartsWith(id + ",")).ToArray();
|
||||
File.WriteAllLines(filePath, filteredLines);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool UpdateConfigration(ConfigrationTable updatedConfig)
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("Configration.csv");
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
string[] lines = File.ReadAllLines(filePath);
|
||||
bool configFound = false;
|
||||
|
||||
for (int i = 1; i < lines.Length; i++)
|
||||
{
|
||||
string[] columns = lines[i].Split(',');
|
||||
|
||||
if (columns.Length < 10)
|
||||
continue;
|
||||
|
||||
if (int.Parse(columns[0]) == updatedConfig.Id)
|
||||
{
|
||||
columns[1] = updatedConfig.Max.ToString();
|
||||
columns[2] = updatedConfig.Min.ToString();
|
||||
columns[3] = string.Join("|", updatedConfig.H_out);
|
||||
columns[4] = string.Join("|", updatedConfig.FC_out);
|
||||
columns[5] = string.Join("|", updatedConfig.SC_out);
|
||||
columns[6] = updatedConfig.kp.ToString();
|
||||
columns[7] = updatedConfig.ki.ToString();
|
||||
columns[8] = updatedConfig.kd.ToString();
|
||||
columns[9] = updatedConfig.kl.ToString();
|
||||
columns[10] = updatedConfig.name;
|
||||
columns[11] = updatedConfig.i_neut.ToString(CultureInfo.InvariantCulture);
|
||||
columns[12] = updatedConfig.i_mot1.ToString(CultureInfo.InvariantCulture);
|
||||
columns[13] = updatedConfig.i_mot2.ToString(CultureInfo.InvariantCulture);
|
||||
columns[14] = updatedConfig.FC_Threshold.ToString(CultureInfo.InvariantCulture);
|
||||
columns[15] = updatedConfig.HeatConRange.ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
lines[i] = string.Join(",", columns);
|
||||
configFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (configFound)
|
||||
{
|
||||
File.WriteAllLines(filePath, lines);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
311
DaireApplication/DataBase/DataPathManager.cs
Normal file
@@ -0,0 +1,311 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DaireApplication.DataBase
|
||||
{
|
||||
public static class DataPathManager
|
||||
{
|
||||
private static readonly string AppName = "DaireApplication";
|
||||
private static string _dataDirectory;
|
||||
|
||||
// Expected CSV headers for each file
|
||||
private static readonly string UsersCsvHeader = "ID,UserName,Password,CanEdit,IsAdmin,IsActive";
|
||||
private static readonly string RecipeCsvHeader = "ID,Name,TankTemp,FountainTemp,Mixer,Fountain,MoldHeater,Vibration,VibHeater,Pedal,PedalOnTime,PedalOffTime,HeatingGoal,CoolingGoal,PouringGoal";
|
||||
private static readonly string MachineCsvHeader = "ID,TankMaxHeat,PumbMaxHeat,PumbDelay,MixerDelay,HeatingDelay,CoolingDelay,PouringDelay,PumbMinHeat,AbsMaxTemp,AbsMinTemp,PreHeatingTemp,SetTemp1,SetTemp2,SetTemp3,SetTemp4";
|
||||
private static readonly string MappingCsvHeader = "Id,Name,Address,IsRead,BitNumbers";
|
||||
private static readonly string ConfigrationCsvHeader = "Id,Max,Min,H_out,FC_out,SC_out,kp,ki,kd,kl,Name,I_Nuet,I_Mot1,I_Mot2,FC_Threshold,HeatConRange";
|
||||
private static readonly string ErrorSettingsCsvHeader = "Id,gridFreq,phaseNumber,extPower,phaseVoltage";
|
||||
private static readonly string ScreenCsvHeader = "Id,Brightness,DimSec,OffSec,Port,BoundRate,Parity,StopBits,SendingTime,WarningLimit,ErrorLimit";
|
||||
|
||||
static DataPathManager()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Determine the data directory based on the OS
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
// Windows: Use LocalApplicationData
|
||||
string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
_dataDirectory = Path.Combine(appDataPath, AppName);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Linux/macOS: Use ~/.local/share/DaireApplication
|
||||
string home = Environment.GetEnvironmentVariable("HOME") ?? "/tmp";
|
||||
_dataDirectory = Path.Combine(home, ".local", "share", AppName);
|
||||
}
|
||||
|
||||
// Ensure the directory exists
|
||||
Directory.CreateDirectory(_dataDirectory);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Failed to CreateDirectory: {ex.Message}");
|
||||
Console.WriteLine($"_dataDirectory: {_dataDirectory}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the full path for a data file, ensuring the directory exists.
|
||||
/// </summary>
|
||||
public static string GetDataFilePath(string fileName)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Ensure the directory exists before returning the file path
|
||||
Directory.CreateDirectory(_dataDirectory);
|
||||
return Path.Combine(_dataDirectory, fileName);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Failed to GetDataFilePath: {ex.Message}");
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Migrates legacy data files from the application's base directory to the new data directory.
|
||||
/// </summary>
|
||||
public static void MigrateLegacyData()
|
||||
{
|
||||
try
|
||||
{
|
||||
string[] csvFiles = { "Users.csv", "Recipe.csv", "Machine.csv", "Mapping.csv",
|
||||
"Configration.csv", "ErrorSettings.csv", "Screen.csv" };
|
||||
|
||||
foreach (string file in csvFiles)
|
||||
{
|
||||
string legacyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, file);
|
||||
string newPath = GetDataFilePath(file);
|
||||
|
||||
// If the file exists in the old location but not in the new location, move it
|
||||
if (File.Exists(legacyPath) && !File.Exists(newPath))
|
||||
{
|
||||
// Ensure the target directory exists
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(newPath) ?? _dataDirectory);
|
||||
File.Move(legacyPath, newPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Failed to MigrateLegacyData: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Migrates CSV files by adding missing columns with default values instead of deleting them.
|
||||
/// </summary>
|
||||
public static void MigrateCsvFiles()
|
||||
{
|
||||
MigrateCsvFile("Users.csv", UsersCsvHeader, GetUsersDefaultValues);
|
||||
MigrateCsvFile("Recipe.csv", RecipeCsvHeader, GetRecipeDefaultValues);
|
||||
MigrateCsvFile("Machine.csv", MachineCsvHeader, GetMachineDefaultValues);
|
||||
MigrateCsvFile("Mapping.csv", MappingCsvHeader, GetMappingDefaultValues);
|
||||
MigrateCsvFile("Configration.csv", ConfigrationCsvHeader, GetConfigrationDefaultValues);
|
||||
MigrateCsvFile("ErrorSettings.csv", ErrorSettingsCsvHeader, GetErrorSettingsDefaultValues);
|
||||
MigrateCsvFile("Screen.csv", ScreenCsvHeader, GetScreenDefaultValues);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Migrates a CSV file by adding missing columns with default values.
|
||||
/// </summary>
|
||||
private static void MigrateCsvFile(string fileName, string expectedHeader, Func<string, string> getDefaultValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
string filePath = GetDataFilePath(fileName);
|
||||
if (!File.Exists(filePath))
|
||||
return;
|
||||
|
||||
string[] lines = File.ReadAllLines(filePath);
|
||||
if (lines.Length == 0)
|
||||
return;
|
||||
|
||||
string actualHeader = lines[0];
|
||||
if (string.Equals(actualHeader.Trim(), expectedHeader.Trim(), StringComparison.OrdinalIgnoreCase))
|
||||
return; // No migration needed
|
||||
|
||||
string[] expectedColumns = expectedHeader.Split(',');
|
||||
string[] actualColumns = actualHeader.Split(',');
|
||||
|
||||
// Find missing columns
|
||||
var missingColumns = new List<(int index, string columnName)>();
|
||||
for (int i = 0; i < expectedColumns.Length; i++)
|
||||
{
|
||||
if (i >= actualColumns.Length || !string.Equals(actualColumns[i].Trim(), expectedColumns[i].Trim(), StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
missingColumns.Add((i, expectedColumns[i]));
|
||||
}
|
||||
}
|
||||
|
||||
if (missingColumns.Count == 0)
|
||||
return;
|
||||
|
||||
// Migrate the file
|
||||
var migratedLines = new List<string>();
|
||||
|
||||
// Add new header
|
||||
migratedLines.Add(expectedHeader);
|
||||
|
||||
// Migrate data rows
|
||||
for (int i = 1; i < lines.Length; i++)
|
||||
{
|
||||
string[] dataColumns = lines[i].Split(',');
|
||||
var newDataColumns = new List<string>(dataColumns);
|
||||
|
||||
// Add missing columns with default values
|
||||
foreach (var missing in missingColumns)
|
||||
{
|
||||
if (missing.index >= newDataColumns.Count)
|
||||
{
|
||||
newDataColumns.Add(getDefaultValue(missing.columnName));
|
||||
}
|
||||
else
|
||||
{
|
||||
newDataColumns.Insert(missing.index, getDefaultValue(missing.columnName));
|
||||
}
|
||||
}
|
||||
|
||||
migratedLines.Add(string.Join(",", newDataColumns));
|
||||
}
|
||||
|
||||
// Write the migrated file
|
||||
File.WriteAllLines(filePath, migratedLines);
|
||||
Console.WriteLine($"Migrated {fileName} - added {missingColumns.Count} missing columns");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Failed to migrate {fileName}: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// Default value providers for each file type
|
||||
private static string GetUsersDefaultValues(string columnName)
|
||||
{
|
||||
return columnName switch
|
||||
{
|
||||
"IsActive" => "0",
|
||||
_ => ""
|
||||
};
|
||||
}
|
||||
|
||||
private static string GetRecipeDefaultValues(string columnName)
|
||||
{
|
||||
return columnName switch
|
||||
{
|
||||
"TankTemp" => "0",
|
||||
"FountainTemp" => "0",
|
||||
"Mixer" => "0",
|
||||
"Fountain" => "0",
|
||||
"MoldHeater" => "0",
|
||||
"Vibration" => "0",
|
||||
"VibHeater" => "0",
|
||||
"Pedal" => "0",
|
||||
"PedalOnTime" => "0",
|
||||
"PedalOffTime" => "0",
|
||||
"HeatingGoal" => "46",
|
||||
"CoolingGoal" => "27",
|
||||
"PouringGoal" => "30",
|
||||
_ => ""
|
||||
};
|
||||
}
|
||||
|
||||
private static string GetMachineDefaultValues(string columnName)
|
||||
{
|
||||
return columnName switch
|
||||
{
|
||||
"TankMaxHeat" => "50",
|
||||
"PumbMaxHeat" => "50",
|
||||
"PumbDelay" => "60",
|
||||
"MixerDelay" => "60",
|
||||
"HeatingDelay" => "60",
|
||||
"CoolingDelay" => "60",
|
||||
"PouringDelay" => "60",
|
||||
"PumbMinHeat" => "-10",
|
||||
"AbsMaxTemp" => "65",
|
||||
"AbsMinTemp" => "-14",
|
||||
"PreHeatingTemp" => "5",
|
||||
"SetTemp1" => "0",
|
||||
"SetTemp2" => "-10",
|
||||
"SetTemp3" => "5",
|
||||
"SetTemp4" => "0",
|
||||
_ => ""
|
||||
};
|
||||
}
|
||||
|
||||
private static string GetMappingDefaultValues(string columnName)
|
||||
{
|
||||
return columnName switch
|
||||
{
|
||||
"BitNumbers" => "",
|
||||
_ => ""
|
||||
};
|
||||
}
|
||||
|
||||
private static string GetConfigrationDefaultValues(string columnName)
|
||||
{
|
||||
return columnName switch
|
||||
{
|
||||
"Max" => "0",
|
||||
"Min" => "0",
|
||||
"H_out" => "",
|
||||
"FC_out" => "",
|
||||
"SC_out" => "",
|
||||
"kp" => "0",
|
||||
"ki" => "0",
|
||||
"kd" => "0",
|
||||
"kl" => "0",
|
||||
"Name" => "",
|
||||
"I_Nuet" => "0",
|
||||
"I_Mot1" => "0",
|
||||
"I_Mot2" => "0",
|
||||
"FC_Threshold" => "3",
|
||||
"HeatConRange" => "50",
|
||||
_ => ""
|
||||
};
|
||||
}
|
||||
|
||||
private static string GetErrorSettingsDefaultValues(string columnName)
|
||||
{
|
||||
return columnName switch
|
||||
{
|
||||
"gridFreq" => "50",
|
||||
"phaseNumber" => "3",
|
||||
"extPower" => "1",
|
||||
"phaseVoltage" => "220",
|
||||
_ => ""
|
||||
};
|
||||
}
|
||||
|
||||
private static string GetScreenDefaultValues(string columnName)
|
||||
{
|
||||
return columnName switch
|
||||
{
|
||||
"Brightness" => "100",
|
||||
"DimSec" => "3300",
|
||||
"OffSec" => "3600",
|
||||
"Port" => "",
|
||||
"BoundRate" => "19200",
|
||||
"Parity" => "1",
|
||||
"StopBits" => "0",
|
||||
"SendingTime" => "50",
|
||||
"WarningLimit" => "0.5",
|
||||
"ErrorLimit" => "2",
|
||||
_ => ""
|
||||
};
|
||||
}
|
||||
|
||||
// Legacy delete methods (kept for backward compatibility but now call migration)
|
||||
public static void DeleteUsersCsv() => MigrateCsvFile("Users.csv", UsersCsvHeader, GetUsersDefaultValues);
|
||||
public static void DeleteRecipeCsv() => MigrateCsvFile("Recipe.csv", RecipeCsvHeader, GetRecipeDefaultValues);
|
||||
public static void DeleteMachineCsv() => MigrateCsvFile("Machine.csv", MachineCsvHeader, GetMachineDefaultValues);
|
||||
public static void DeleteMappingCsv() => MigrateCsvFile("Mapping.csv", MappingCsvHeader, GetMappingDefaultValues);
|
||||
public static void DeleteConfigrationCsv() => MigrateCsvFile("Configration.csv", ConfigrationCsvHeader, GetConfigrationDefaultValues);
|
||||
public static void DeleteErrorSettingsCsv() => MigrateCsvFile("ErrorSettings.csv", ErrorSettingsCsvHeader, GetErrorSettingsDefaultValues);
|
||||
public static void DeleteScreenCsv() => MigrateCsvFile("Screen.csv", ScreenCsvHeader, GetScreenDefaultValues);
|
||||
}
|
||||
}
|
||||
81
DaireApplication/DataBase/ErrorSettingsTable.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DaireApplication.DataBase
|
||||
{
|
||||
public class ErrorSettingsTable
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public int gridFreq { get; set; }
|
||||
public int phaseNumber { get; set; }
|
||||
public int phaseVoltage { get; set; }
|
||||
public bool extPower { get; set; }
|
||||
|
||||
public List<ErrorSettingsTable>? ReadErrorSettings()
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("ErrorSettings.csv");
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
return null;
|
||||
|
||||
string[] lines = File.ReadAllLines(filePath);
|
||||
List<ErrorSettingsTable> errors = new();
|
||||
|
||||
for (int i = 1; i < lines.Length; i++)
|
||||
{
|
||||
string[] columns = lines[i].Split(',');
|
||||
|
||||
errors.Add(new ErrorSettingsTable
|
||||
{
|
||||
Id = int.Parse(columns[0]),
|
||||
gridFreq = int.Parse(columns[1]),
|
||||
phaseNumber = int.Parse(columns[2]),
|
||||
extPower = columns[3] == "1",
|
||||
phaseVoltage = int.Parse(columns[4]),
|
||||
});
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
public bool UpdateError(ErrorSettingsTable updatedError)
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("ErrorSettings.csv");
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
return false;
|
||||
|
||||
string[] lines = File.ReadAllLines(filePath);
|
||||
bool updated = false;
|
||||
|
||||
for (int i = 1; i < lines.Length; i++)
|
||||
{
|
||||
string[] columns = lines[i].Split(',');
|
||||
|
||||
if (int.Parse(columns[0]) == updatedError.Id)
|
||||
{
|
||||
columns[1] = updatedError.gridFreq.ToString();
|
||||
columns[2] = updatedError.phaseNumber.ToString();
|
||||
columns[3] = updatedError.extPower ? "1" : "0";
|
||||
columns[4] = updatedError.phaseVoltage .ToString();
|
||||
lines[i] = string.Join(",", columns);
|
||||
updated = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (updated)
|
||||
{
|
||||
File.WriteAllLines(filePath, lines);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
124
DaireApplication/DataBase/MachineTable.cs
Normal file
@@ -0,0 +1,124 @@
|
||||
using AvaloniaApplication1.DataBase;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DaireApplication.DataBase
|
||||
{
|
||||
public class MachineTable
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public float TankMaxHeat { get; set; } = 50;
|
||||
public float PumbMaxHeat { get; set; } = 50;
|
||||
public int PumbDelay { get; set; } = 60;
|
||||
public int MixerDelay { get; set; } = 60;
|
||||
public int HeatingDelay { get; set; } = 60;
|
||||
public int CoolingDelay { get; set; } = 60;
|
||||
public int PouringDelay { get; set; } = 60;
|
||||
public float PumbMinHeat { get; set; } = -10;
|
||||
public float AbsMaxHeat { get; set; } = 65;
|
||||
public float AbsMinHeat { get; set; } = -14;
|
||||
public float PreHeatingTemp { get; set; } = 5;
|
||||
public float setTemp1 { get; set; } =0;
|
||||
public float setTemp2 { get; set; } =-10;
|
||||
public float setTemp3 { get; set; } =+5;
|
||||
public float setTemp4 { get; set; } =+0;
|
||||
|
||||
public MachineTable ReadMachine()
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("Machine.csv");
|
||||
MachineTable machine = new MachineTable();
|
||||
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
string[] lines = File.ReadAllLines(filePath);
|
||||
|
||||
foreach (string line in lines)
|
||||
{
|
||||
string[] columns = line.Split(',');
|
||||
|
||||
if (columns[0] == "1")
|
||||
{
|
||||
machine.Id = int.Parse(columns[0]);
|
||||
machine.TankMaxHeat = float.Parse(columns[1]);
|
||||
machine.PumbMaxHeat = float.Parse(columns[2]);
|
||||
machine.PumbDelay = int.Parse(columns[3]);
|
||||
machine.MixerDelay = int.Parse(columns[4]);
|
||||
machine.HeatingDelay = int.Parse(columns[5]);
|
||||
machine.CoolingDelay = int.Parse(columns[6]);
|
||||
machine.PouringDelay = int.Parse(columns[7]);
|
||||
machine.PumbMinHeat = int.Parse(columns[8]);
|
||||
machine.AbsMaxHeat = int.Parse(columns[9]);
|
||||
machine.AbsMinHeat = int.Parse(columns[10]);
|
||||
machine.PreHeatingTemp = float.Parse(columns[11]);
|
||||
machine.setTemp1 = float.Parse(columns[12]);
|
||||
machine.setTemp2 = float.Parse(columns[13]);
|
||||
machine.setTemp3 = float.Parse(columns[14]);
|
||||
machine.setTemp4 = float.Parse(columns[15]);
|
||||
return machine;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public bool UpdateMachine(MachineTable updatedMachine)
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("Machine.csv");
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
return false;
|
||||
|
||||
string[] lines = File.ReadAllLines(filePath);
|
||||
bool machineFound = false;
|
||||
|
||||
for (int i = 1; i < lines.Length; i++)
|
||||
{
|
||||
string[] columns = lines[i].Split(',');
|
||||
|
||||
if (columns.Length < 8)
|
||||
continue;
|
||||
|
||||
if (int.Parse(columns[0]) == updatedMachine.Id)
|
||||
{
|
||||
columns[1] = updatedMachine.TankMaxHeat.ToString(CultureInfo.InvariantCulture);
|
||||
columns[2] = updatedMachine.PumbMaxHeat.ToString(CultureInfo.InvariantCulture);
|
||||
columns[3] = updatedMachine.PumbDelay.ToString();
|
||||
columns[4] = updatedMachine.MixerDelay.ToString();
|
||||
columns[5] = updatedMachine.HeatingDelay.ToString();
|
||||
columns[6] = updatedMachine.CoolingDelay.ToString();
|
||||
columns[7] = updatedMachine.PouringDelay.ToString();
|
||||
columns[8] = updatedMachine.PumbMinHeat.ToString(CultureInfo.InvariantCulture);
|
||||
columns[9] = updatedMachine.AbsMaxHeat.ToString(CultureInfo.InvariantCulture);
|
||||
columns[10] = updatedMachine.AbsMinHeat.ToString(CultureInfo.InvariantCulture);
|
||||
columns[11] = updatedMachine.PreHeatingTemp.ToString(CultureInfo.InvariantCulture);
|
||||
columns[12] = updatedMachine.setTemp1.ToString(CultureInfo.InvariantCulture);
|
||||
columns[13] = updatedMachine.setTemp2.ToString(CultureInfo.InvariantCulture);
|
||||
columns[14] = updatedMachine.setTemp3.ToString(CultureInfo.InvariantCulture);
|
||||
columns[15] = updatedMachine.setTemp4.ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
lines[i] = string.Join(",", columns);
|
||||
machineFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (machineFound)
|
||||
{
|
||||
File.WriteAllLines(filePath, lines);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
196
DaireApplication/DataBase/Mapping.cs
Normal file
@@ -0,0 +1,196 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace DaireApplication.DataBase;
|
||||
|
||||
public class Mapping
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; } = "";
|
||||
public string Address { get; set; } = "";
|
||||
public bool IsRead { get; set; } = false;
|
||||
public List<int> BitNumbers { get; set; } = new();
|
||||
|
||||
|
||||
public ushort getSetTempAddress(int tempAddress)
|
||||
{
|
||||
string tAddress = "4000";
|
||||
tempAddress -= 30004;
|
||||
tAddress += tempAddress;
|
||||
return ushort.Parse(tAddress);
|
||||
}
|
||||
public List<Mapping> ReadMappings()
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("Mapping.csv");
|
||||
List<Mapping> mappings = new();
|
||||
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
using StreamReader reader = new(filePath);
|
||||
string header = reader.ReadLine();
|
||||
while (!reader.EndOfStream)
|
||||
{
|
||||
string[] columns = reader.ReadLine().Split(',');
|
||||
mappings.Add(new Mapping
|
||||
{
|
||||
Id = int.Parse(columns[0]),
|
||||
Name = columns[1],
|
||||
Address = columns[2],
|
||||
IsRead = columns[3] == "1"|| columns[3] == "True",
|
||||
BitNumbers =columns[4]!=""? columns[4].Split('|').Select(int.Parse).ToList():new List<int>()
|
||||
});
|
||||
}
|
||||
return mappings;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int GetMaxId()
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("Mapping.csv");
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
return File.ReadAllLines(filePath)
|
||||
.Select(line => line.Split(','))
|
||||
.Where(columns => columns.Length > 0)
|
||||
.Select(columns => int.TryParse(columns[0], out int id) ? id : 0)
|
||||
.Max();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public Mapping ReadMappingById(string id)
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("Mapping.csv");
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
foreach (var line in File.ReadLines(filePath))
|
||||
{
|
||||
string[] columns = line.Split(',');
|
||||
if (columns[0] == id)
|
||||
{
|
||||
return new Mapping
|
||||
{
|
||||
Id = int.Parse(columns[0]),
|
||||
Name = columns[1],
|
||||
Address = columns[2],
|
||||
IsRead = columns[3] == "1",
|
||||
BitNumbers = columns[4].Split('|').Select(int.Parse).ToList()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool AddMapping(Mapping data)
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("Mapping.csv");
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
string newEntry = string.Join(",", [
|
||||
GetMaxId() + 1,
|
||||
data.Name,
|
||||
data.Address,
|
||||
data.IsRead ? "1" : "0",
|
||||
string.Join("|", data.BitNumbers)
|
||||
]);
|
||||
File.AppendAllText(filePath, newEntry + Environment.NewLine);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool DeleteMapping(string id)
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("Mapping.csv");
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
var filteredLines = File.ReadLines(filePath).Where(line => !line.StartsWith(id + ",")).ToArray();
|
||||
File.WriteAllLines(filePath, filteredLines);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool UpdateMapping(Mapping updatedMapping)
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("Mapping.csv");
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
string[] lines = File.ReadAllLines(filePath);
|
||||
bool mappingFound = false;
|
||||
|
||||
for (int i = 1; i < lines.Length; i++)
|
||||
{
|
||||
string[] columns = lines[i].Split(',');
|
||||
|
||||
if (columns.Length < 5)
|
||||
continue;
|
||||
|
||||
if (int.Parse(columns[0]) == updatedMapping.Id)
|
||||
{
|
||||
columns[1] = updatedMapping.Name;
|
||||
columns[2] = updatedMapping.Address;
|
||||
columns[3] = updatedMapping.IsRead ? "1" : "0";
|
||||
columns[4] = string.Join("|", updatedMapping.BitNumbers);
|
||||
lines[i] = string.Join(",", columns);
|
||||
mappingFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mappingFound)
|
||||
{
|
||||
File.WriteAllLines(filePath, lines);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool DeleteBitNumber(int id, int bitNumber)
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("Mapping.csv");
|
||||
if (!File.Exists(filePath))
|
||||
return false;
|
||||
|
||||
List<Mapping> records = ReadMappings();
|
||||
Mapping? record = records.Find(x => x.Id == id);
|
||||
|
||||
if (record != null && record.BitNumbers.Remove(bitNumber)) // Remove bit number if found
|
||||
{
|
||||
string header;
|
||||
using (StreamReader sr = new StreamReader(filePath))
|
||||
{
|
||||
header = sr.ReadLine() ?? string.Empty;
|
||||
}
|
||||
|
||||
using (StreamWriter writer = new StreamWriter(filePath))
|
||||
{
|
||||
writer.WriteLine(header);
|
||||
string bitNumbersStr = "";
|
||||
foreach (var rec in records)
|
||||
{
|
||||
if (rec.Id==id)
|
||||
{
|
||||
bitNumbersStr = record.BitNumbers.Count > 0 ? string.Join("|", record.BitNumbers) : "";
|
||||
writer.WriteLine($"{rec.Id},{rec.Name},{rec.Address},{rec.IsRead},{bitNumbersStr}");
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
bitNumbersStr = rec.BitNumbers.Count > 0 ? string.Join("|", rec.BitNumbers) : "";
|
||||
writer.WriteLine($"{rec.Id},{rec.Name},{rec.Address},{rec.IsRead},{bitNumbersStr}");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
239
DaireApplication/DataBase/RecipeTable.cs
Normal file
@@ -0,0 +1,239 @@
|
||||
using DaireApplication.DataBase;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace AvaloniaApplication1.DataBase
|
||||
{
|
||||
public class RecipeTable
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public float TankTemp { get; set; } = 0;
|
||||
public float FountainTemp { get; set; } = 0;
|
||||
public bool? Mixer { get; set; } = false;
|
||||
public bool? Fountain { get; set; }=false;
|
||||
public bool? MoldHeater { get; set; }=false;
|
||||
public bool? Vibration { get; set; } = false;
|
||||
public bool? VibHeater { get; set; } = false;
|
||||
public bool? Pedal { get; set; } = false;
|
||||
public int PedalOnTime { get; set; } = 0;
|
||||
public int PedalOffTime { get; set; } = 0;
|
||||
public float HeatingGoal { get; set; } = 46;
|
||||
public float CoolingGoal { get; set; } = 27;
|
||||
public float PouringGoal { get; set; } = 30;
|
||||
|
||||
public RecipeTable()
|
||||
{
|
||||
Mixer = null;
|
||||
Fountain = null;
|
||||
MoldHeater = null;
|
||||
Vibration = null;
|
||||
VibHeater = null;
|
||||
Pedal = null;
|
||||
}
|
||||
|
||||
|
||||
public List<RecipeTable> ReadRecipes()
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("Recipe.csv");
|
||||
List<RecipeTable> recipes = new List<RecipeTable>();
|
||||
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
using (StreamReader reader = new StreamReader(filePath))
|
||||
{
|
||||
// Skip header
|
||||
string header = reader.ReadLine();
|
||||
while (!reader.EndOfStream)
|
||||
{
|
||||
string line = reader.ReadLine();
|
||||
string[] columns = line.Split(',');
|
||||
recipes.Add(new RecipeTable
|
||||
{
|
||||
Id = int.Parse(columns[0]),
|
||||
Name = columns[1],
|
||||
TankTemp = float.Parse(columns[2]),
|
||||
FountainTemp = float.Parse(columns[3]),
|
||||
Mixer = columns[4] == "1",
|
||||
Fountain = columns[5] == "1",
|
||||
MoldHeater = columns[6]=="1",
|
||||
Vibration = columns[7] == "1",
|
||||
VibHeater = columns[8]== "1",
|
||||
Pedal = columns[9]=="1",
|
||||
PedalOnTime = int.Parse(columns[10]),
|
||||
PedalOffTime = int.Parse(columns[11]),
|
||||
HeatingGoal = float.Parse(columns[12]),
|
||||
CoolingGoal = float.Parse(columns[13]),
|
||||
PouringGoal = float.Parse(columns[14]),
|
||||
});
|
||||
}
|
||||
}
|
||||
return recipes;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public bool DoesNameExist(string searchName)
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("Recipe.csv");
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
return false;
|
||||
|
||||
string[] lines = File.ReadAllLines(filePath);
|
||||
|
||||
return lines
|
||||
.Select(line => line.Split(','))
|
||||
.Where(columns => columns.Length > 1)
|
||||
.Any(columns => string.Equals(columns[1].Trim(), searchName, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
public int GetMaxId()
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("Recipe.csv");
|
||||
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
string[] lines = File.ReadAllLines(filePath);
|
||||
int maxId = lines
|
||||
.Select(line => line.Split(','))
|
||||
.Where(columns => columns.Length > 0)
|
||||
.Select(columns => int.TryParse(columns[0], out int id) ? id : 0)
|
||||
.Max();
|
||||
return maxId;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
public RecipeTable ReadRecipesById(string id)
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("Recipe.csv");
|
||||
RecipeTable recipe = new RecipeTable();
|
||||
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
string[] lines = File.ReadAllLines(filePath);
|
||||
|
||||
foreach (string line in lines)
|
||||
{
|
||||
string[] columns = line.Split(',');
|
||||
|
||||
if (columns[0] == id)
|
||||
{
|
||||
recipe.Id = int.Parse(columns[0]);
|
||||
recipe.Name = columns[1];
|
||||
recipe.TankTemp = float.Parse(columns[2]);
|
||||
recipe.FountainTemp = float.Parse(columns[3]);
|
||||
recipe.Mixer = columns[4] == "1";
|
||||
recipe.Fountain = columns[5] == "1";
|
||||
recipe.MoldHeater = columns[6] == "1";
|
||||
recipe.Vibration = columns[7] == "1";
|
||||
recipe.VibHeater = columns[8] == "1";
|
||||
recipe.Pedal = columns[9] == "1";
|
||||
recipe.PedalOnTime = int.Parse(columns[10]);
|
||||
recipe.PedalOffTime = int.Parse(columns[11]);
|
||||
recipe.HeatingGoal = float.Parse(columns[12]);
|
||||
recipe.CoolingGoal = float.Parse(columns[13]);
|
||||
recipe.PouringGoal = float.Parse(columns[14]);
|
||||
return recipe;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public bool AddRecipe(RecipeTable data)
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("Recipe.csv");
|
||||
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
string newEntry = string.Join(",", [GetMaxId() +1, data.Name,data.TankTemp, data.FountainTemp, data.Mixer.Value?"1":"0", data.Fountain.Value ? "1" : "0", data.MoldHeater.Value ? "1" : "0", data.Vibration.Value ? "1" : "0", data.VibHeater.Value ? "1" : "0", data.Pedal.Value ? "1":"0",data.PedalOnTime,data.PedalOffTime, data.HeatingGoal,data.CoolingGoal,data.PouringGoal]);
|
||||
|
||||
File.AppendAllText(filePath, newEntry + Environment.NewLine);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public bool DeleteRecipe(string id)
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("Recipe.csv");
|
||||
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
string[] lines = File.ReadAllLines(filePath);
|
||||
var filteredLines = lines.Where(line => !line.StartsWith(id + ",")).ToArray();
|
||||
|
||||
File.WriteAllLines(filePath, filteredLines);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool UpdateRecipe(RecipeTable updatedRecipe)
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("Recipe.csv");
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
return false;
|
||||
|
||||
string[] lines = File.ReadAllLines(filePath);
|
||||
bool recipeFound = false;
|
||||
|
||||
for (int i = 1; i < lines.Length; i++)
|
||||
{
|
||||
string[] columns = lines[i].Split(',');
|
||||
|
||||
if (columns.Length < 15)
|
||||
continue;
|
||||
|
||||
if (int.TryParse(columns[0], out int id) && id == updatedRecipe.Id)
|
||||
{
|
||||
columns[1] = updatedRecipe.Name ?? "";
|
||||
columns[2] = updatedRecipe.TankTemp.ToString(CultureInfo.InvariantCulture);
|
||||
columns[3] = updatedRecipe.FountainTemp.ToString(CultureInfo.InvariantCulture);
|
||||
columns[4] = (updatedRecipe.Mixer ?? false) ? "1" : "0";
|
||||
columns[5] = (updatedRecipe.Fountain ?? false) ? "1" : "0";
|
||||
columns[6] = (updatedRecipe.MoldHeater ?? false) ? "1" : "0";
|
||||
columns[7] = (updatedRecipe.Vibration ?? false) ? "1" : "0";
|
||||
columns[8] = (updatedRecipe.VibHeater ?? false) ? "1" : "0";
|
||||
columns[9] = (updatedRecipe.Pedal ?? false) ? "1" : "0";
|
||||
columns[10] = updatedRecipe.PedalOnTime.ToString();
|
||||
columns[11] = updatedRecipe.PedalOffTime.ToString();
|
||||
columns[12] = updatedRecipe.HeatingGoal.ToString(CultureInfo.InvariantCulture);
|
||||
columns[13] = updatedRecipe.CoolingGoal.ToString(CultureInfo.InvariantCulture);
|
||||
columns[14] = updatedRecipe.PouringGoal.ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
lines[i] = string.Join(",", columns);
|
||||
recipeFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (recipeFound)
|
||||
{
|
||||
File.WriteAllLines(filePath, lines);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
112
DaireApplication/DataBase/ScreeenTable.cs
Normal file
@@ -0,0 +1,112 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DaireApplication.DataBase
|
||||
{
|
||||
public class ScreeenTable
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public int brightness { get; set; }
|
||||
public float dimSec { get; set; }
|
||||
public float offSec { get; set; }
|
||||
public string port { get; set; }
|
||||
public int boundRate { get; set; }
|
||||
public int stopBits { get; set; }
|
||||
public int parity { get; set; }
|
||||
public int sendingTime { get; set; }
|
||||
public double warningLimit { get; set; }
|
||||
public double errorLimit { get; set; }
|
||||
|
||||
public List<ScreeenTable>? ReadScreens()
|
||||
{
|
||||
try
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("Screen.csv");
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
return null;
|
||||
|
||||
string[] lines = File.ReadAllLines(filePath);
|
||||
List<ScreeenTable> screens = new();
|
||||
|
||||
for (int i = 1; i < lines.Length; i++)
|
||||
{
|
||||
string[] columns = lines[i].Split(',');
|
||||
|
||||
if (columns.Length < 8)
|
||||
continue;
|
||||
|
||||
screens.Add(new ScreeenTable
|
||||
{
|
||||
Id = int.Parse(columns[0]),
|
||||
brightness = int.Parse(columns[1]),
|
||||
dimSec = float.Parse(columns[2]),
|
||||
offSec = float.Parse(columns[3]),
|
||||
port = columns[4],
|
||||
boundRate = int.Parse(columns[5]),
|
||||
stopBits = int.Parse(columns[6]),
|
||||
parity = int.Parse(columns[7]),
|
||||
sendingTime = int.Parse(columns[8]),
|
||||
warningLimit = double.Parse(columns[9]),
|
||||
errorLimit = double.Parse(columns[10]),
|
||||
});
|
||||
}
|
||||
|
||||
return screens;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public bool UpdateScreen(ScreeenTable updatedScreen)
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("Screen.csv");
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
return false;
|
||||
|
||||
string[] lines = File.ReadAllLines(filePath);
|
||||
bool updated = false;
|
||||
|
||||
for (int i = 1; i < lines.Length; i++)
|
||||
{
|
||||
string[] columns = lines[i].Split(',');
|
||||
|
||||
if (columns.Length < 8)
|
||||
continue;
|
||||
|
||||
if (int.Parse(columns[0]) == updatedScreen.Id)
|
||||
{
|
||||
columns[1] = updatedScreen.brightness.ToString();
|
||||
columns[2] = updatedScreen.dimSec.ToString();
|
||||
columns[3] = updatedScreen.offSec.ToString();
|
||||
columns[4] = updatedScreen.port;
|
||||
columns[5] = updatedScreen.boundRate.ToString();
|
||||
columns[6] = updatedScreen.stopBits.ToString();
|
||||
columns[7] = updatedScreen.parity.ToString();
|
||||
columns[8] = updatedScreen.sendingTime.ToString();
|
||||
columns[9] = updatedScreen.warningLimit.ToString();
|
||||
columns[10] = updatedScreen.errorLimit.ToString();
|
||||
|
||||
lines[i] = string.Join(",", columns);
|
||||
updated = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (updated)
|
||||
{
|
||||
File.WriteAllLines(filePath, lines);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
83
DaireApplication/DataBase/UserTable.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
using DaireApplication.DataBase;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AvaloniaApplication1.DataBase
|
||||
{
|
||||
public class UserTable
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string UserName { get; set; }
|
||||
public string Password { get; set; }
|
||||
public bool CanEdit { get; set; }
|
||||
public bool IsAdmin { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
|
||||
public List<UserTable> ReadUsers()
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("Users.csv");
|
||||
List<UserTable> users = new List<UserTable>();
|
||||
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
string[] lines = File.ReadAllLines(filePath);
|
||||
|
||||
for (int i = 1; i < lines.Length; i++) // Skip header
|
||||
{
|
||||
string[] columns = lines[i].Split(',');
|
||||
users.Add(new UserTable
|
||||
{
|
||||
Id = int.Parse(columns[0]),
|
||||
UserName = columns[1],
|
||||
Password = columns[2],
|
||||
CanEdit = columns[3] =="1" ?true:false,
|
||||
IsAdmin=columns[4] =="1" ?true: false,
|
||||
IsActive=columns[5] =="1" ?true: false,
|
||||
});
|
||||
}
|
||||
return users;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public bool UpdateUser(UserTable updatedUser)
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("Users.csv");
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
string[] lines = File.ReadAllLines(filePath);
|
||||
bool userFound = false;
|
||||
|
||||
for (int i = 1; i < lines.Length; i++)
|
||||
{
|
||||
string[] columns = lines[i].Split(',');
|
||||
if (int.Parse(columns[0]) == updatedUser.Id)
|
||||
{
|
||||
columns[1] = updatedUser.UserName;
|
||||
columns[2] = updatedUser.Password;
|
||||
columns[3] = updatedUser.CanEdit ? "1" : "0";
|
||||
columns[4] = updatedUser.IsAdmin ? "1" : "0";
|
||||
columns[5] = updatedUser.IsActive ? "1" : "0";
|
||||
lines[i] = string.Join(",", columns);
|
||||
userFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (userFound)
|
||||
{
|
||||
File.WriteAllLines(filePath, lines);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
111
DaireApplication/Loops/CheckInterNetLoop.cs
Normal file
@@ -0,0 +1,111 @@
|
||||
using Avalonia.Media.Imaging;
|
||||
using Avalonia.Threading;
|
||||
using DaireApplication.ViewModels;
|
||||
using DaireApplication.Views;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DaireApplication.Loops
|
||||
{
|
||||
public class CheckInterNetLoop
|
||||
{
|
||||
public static async void CheckInterNet(MainWindow _mainWindow)
|
||||
{
|
||||
string textToDelete = "";
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (!Error.IsInternetAvailable())
|
||||
{
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
if (_mainWindow.ContentArea.Content is Home || _mainWindow.ContentArea.Content is Admin)
|
||||
{
|
||||
if (!_mainWindow.nowifiLogo.IsVisible)
|
||||
{
|
||||
_mainWindow.wifiLogo.IsVisible = false;
|
||||
_mainWindow.nowifiLogo.IsVisible = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_mainWindow.wifiLogo.IsVisible = false;
|
||||
_mainWindow.nowifiLogo.IsVisible = false;
|
||||
}
|
||||
//if (!_mainWindow.warningMsg.Text.Contains("No Internet Access"))
|
||||
//{
|
||||
// _mainWindow.warningMsg.Text += "\nNo Internet Access";
|
||||
// _mainWindow.warningLogo.IsVisible = true;
|
||||
|
||||
//}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
if (_mainWindow.ContentArea.Content is Home || _mainWindow.ContentArea.Content is Admin)
|
||||
{
|
||||
if (!_mainWindow.wifiLogo.IsVisible)
|
||||
{
|
||||
_mainWindow.nowifiLogo.IsVisible = false;
|
||||
_mainWindow.wifiLogo.IsVisible = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_mainWindow.wifiLogo.IsVisible = false;
|
||||
_mainWindow.nowifiLogo.IsVisible = false;
|
||||
}
|
||||
//if (_mainWindow.warningMsg.Text.Contains("No Internet Access"))
|
||||
//{
|
||||
// _mainWindow.warningMsg.Text=_mainWindow.warningMsg.Text.Replace("\nNo Internet Access", "");
|
||||
//}
|
||||
});
|
||||
|
||||
}
|
||||
if (!string.IsNullOrEmpty(_mainWindow.warningMessage))
|
||||
{
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
if (!_mainWindow.warningMsg.Text.Contains($"\n-{_mainWindow.warningMessage}"))
|
||||
{
|
||||
textToDelete = _mainWindow.warningMessage;
|
||||
_mainWindow.warningMsg.Text += $"\n-{_mainWindow.warningMessage}";
|
||||
_mainWindow.warningLogo.IsVisible = true;
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
if (_mainWindow.warningMsg.Text.Contains($"-{textToDelete}"))
|
||||
{
|
||||
_mainWindow.warningMsg.Text= _mainWindow.warningMsg.Text.Replace($"\n-{textToDelete}", "");
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
if ( string.IsNullOrEmpty(_mainWindow.warningMessage))
|
||||
{
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
_mainWindow.warningLogo.IsVisible = false;
|
||||
|
||||
});
|
||||
}
|
||||
Thread.Sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
100
DaireApplication/Loops/InteractiveUILoop.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Threading;
|
||||
using AvaloniaApplication1.ViewModels;
|
||||
using DaireApplication.DataBase;
|
||||
using DaireApplication.Views;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DaireApplication.Loops
|
||||
{
|
||||
public class InteractiveUILoop
|
||||
{
|
||||
public static async void Flashing(MainWindow _mainWindow)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
// Flashing Pre Heater on
|
||||
if (_mainWindow.isFlashPreHeating)
|
||||
{
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
if (_mainWindow.PreHeatingBtn.Foreground == Brushes.Transparent)
|
||||
{
|
||||
_mainWindow.PreHeatingBtn.Foreground = Brushes.White;
|
||||
}
|
||||
else
|
||||
{
|
||||
_mainWindow.PreHeatingBtn.Foreground = Brushes.Transparent;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
// Flashing Pre Heater off
|
||||
if (!_mainWindow.isFlashPreHeating)
|
||||
{
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
_mainWindow.PreHeatingBtn.Foreground = Brushes.White;
|
||||
});
|
||||
}
|
||||
// Flashing Mixer on
|
||||
if (_mainWindow.startMixerMotorFlashing == 1)
|
||||
{
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
if (_mainWindow.ContentArea.Content is Settings result)
|
||||
{
|
||||
var motorLable = result.MixerSP.Children[1] as Avalonia.Controls.Label;
|
||||
var motorRectangel = result.MixerSP.Children[2] as Avalonia.Controls.Shapes.Rectangle;
|
||||
if (motorLable.Foreground.ToString() == "#ff231f20")
|
||||
{
|
||||
motorLable.Foreground = Brushes.Transparent ;
|
||||
motorRectangel.Fill = Brushes.Transparent;
|
||||
}
|
||||
else
|
||||
{
|
||||
motorLable.Foreground = Brush.Parse("#ff231f20");
|
||||
motorRectangel.Fill = Brush.Parse(_mainWindow.PassiveColor);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
// Flashing Fountain on (only when not in pedal auto mode)
|
||||
if (_mainWindow.startFountainMotorFlashing == 1 && !_mainWindow.isPedalAutoMode)
|
||||
{
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
if (_mainWindow.ContentArea.Content is Settings result)
|
||||
{
|
||||
var fountainLable = result.FountainSP.Children[1] as Avalonia.Controls.Label;
|
||||
var fountainRectangel = result.FountainSP.Children[2] as Avalonia.Controls.Shapes.Rectangle;
|
||||
if (fountainLable.Foreground.ToString() == "#ff231f20")
|
||||
{
|
||||
fountainLable.Foreground = Brushes.Transparent;
|
||||
fountainRectangel.Fill = Brushes.Transparent;
|
||||
}
|
||||
else
|
||||
{
|
||||
fountainLable.Foreground = Brush.Parse("#ff231f20");
|
||||
fountainRectangel.Fill = Brush.Parse(_mainWindow.PassiveColor);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
Thread.Sleep(250);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
172
DaireApplication/Loops/ScreenLoop.cs
Normal file
@@ -0,0 +1,172 @@
|
||||
using Avalonia.Threading;
|
||||
using DaireApplication.Views;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DaireApplication.Loops;
|
||||
|
||||
public class ScreenLoop
|
||||
{
|
||||
static void SetBrightness(int value)
|
||||
{
|
||||
//File.WriteAllText("/sys/class/backlight/backlight/brightness", value.ToString());
|
||||
}
|
||||
public static async void Screen(MainWindow _mainWindow)
|
||||
{
|
||||
var screenData = _mainWindow._screeen.ReadScreens()?[0];
|
||||
SetBrightness((int)(screenData.brightness / 100 * 255));
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
screenData = _mainWindow._screeen.ReadScreens()?[0];
|
||||
|
||||
if ((DateTime.Now - _mainWindow.lastActivity).TotalSeconds >= screenData?.offSec)
|
||||
{
|
||||
if (!MainWindow.isOff)
|
||||
{
|
||||
MainWindow.isOff = true;
|
||||
SetBrightness(0);
|
||||
}
|
||||
|
||||
}
|
||||
else if ((DateTime.Now - _mainWindow.lastActivity).TotalSeconds >= screenData?.dimSec)
|
||||
{
|
||||
MainWindow.isOff = false;
|
||||
SetBrightness(51); // 20% of 255
|
||||
}
|
||||
|
||||
if (MainWindow.errors.Count > 0)
|
||||
{
|
||||
foreach (var item in MainWindow.errors.ToList())
|
||||
{
|
||||
|
||||
if ((DateTime.Now - item.errorDate).TotalSeconds >= 2.5)
|
||||
{
|
||||
if (!item.isShowen)
|
||||
{
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
if (_mainWindow.errorMsg.Text.Contains($"- {item.GetDisplayNames(item.Condition)}"))
|
||||
{
|
||||
item.isShowen = true;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
_mainWindow.errorMsg.Text += $"\n- {item.GetDisplayNames(item.Condition)}";
|
||||
item.isShowen = true;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
if (item.isDeleted)
|
||||
{
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
_mainWindow.errorMsg.Text = _mainWindow.errorMsg.Text
|
||||
.Replace($"- {item.GetDisplayNames(item.Condition)}", "");
|
||||
MainWindow.errors.Remove(item);
|
||||
});
|
||||
}
|
||||
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
_mainWindow.errorMsg.Text = _mainWindow.errorMsg.Text.Trim();
|
||||
if (_mainWindow.ContentArea.Content is Settings settings && MainWindow.errors.Count > 0)
|
||||
{
|
||||
//_mainWindow.footerMsg.Text = "";
|
||||
settings.mixerBtn.IsEnabled = false;
|
||||
settings.fountainBtn.IsEnabled = false;
|
||||
settings.moldHeaterBtn.IsEnabled = false;
|
||||
settings.vibrationBtn.IsEnabled = false;
|
||||
settings.vibHeaterBtn.IsEnabled = false;
|
||||
_mainWindow.PreHeatingBtn.IsEnabled = false;
|
||||
//_mainWindow.recipeStartBtn.IsEnabled = false;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (MainWindow.errors.Count > 0)
|
||||
{
|
||||
if ((DateTime.Now - MainWindow.errors.Min(x => x.errorDate)).TotalSeconds >= 3.5)
|
||||
{
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
_mainWindow.errorLogo.IsVisible = true;
|
||||
|
||||
_mainWindow.errorTitel.Text = $"Error Number: {MainWindow.errors.Count}";
|
||||
_mainWindow.errorMsg.Text = _mainWindow.errorMsg.Text.Trim();
|
||||
|
||||
//_mainWindow.footerMsg.Text = $"Error Numbers: {MainWindow.errors.Count}";
|
||||
//_mainWindow.errorLogoBtn.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
|
||||
//MainWindow.errors.Clear();
|
||||
_mainWindow.errorLogo.IsVisible = false;
|
||||
_mainWindow.errorPopupOverlay.IsVisible = false;
|
||||
if (_mainWindow.ContentArea.Content is Settings settings)
|
||||
{
|
||||
//_mainWindow.footerMsg.Text = "Ready";
|
||||
|
||||
settings.moldHeaterBtn.IsEnabled = true;
|
||||
settings.vibrationBtn.IsEnabled = true;
|
||||
settings.vibHeaterBtn.IsEnabled = true;
|
||||
_mainWindow.recipeStartBtn.IsEnabled = true;
|
||||
if (_mainWindow.startRecipe != 1)
|
||||
{
|
||||
_mainWindow.PreHeatingBtn.IsEnabled = true;
|
||||
settings.mixerBtn.IsEnabled = true;
|
||||
settings.fountainBtn.IsEnabled = true;
|
||||
|
||||
}
|
||||
var isFountOn = false;
|
||||
var isMixerOn = false;
|
||||
var fountainMotor =_mainWindow._mapping.Find(x => x.Name.ToLower() == "Helix".ToLower());
|
||||
var mixerMotor =_mainWindow._mapping.Find(x => x.Name.ToLower() == "Mixer".ToLower());
|
||||
if (isFountOn !=fountainMotor.BitNumbers.All(bit => (_mainWindow.holdingRegister.motor & (1 << bit)) != 0))
|
||||
{
|
||||
isFountOn = fountainMotor.BitNumbers.All(bit => (_mainWindow.holdingRegister.motor & (1 << bit)) != 0);
|
||||
}
|
||||
if (isMixerOn != mixerMotor.BitNumbers.All(bit => (_mainWindow.holdingRegister.motor & (1 << bit)) != 0))
|
||||
{
|
||||
isMixerOn = mixerMotor.BitNumbers.All(bit => (_mainWindow.holdingRegister.motor & (1 << bit)) != 0);
|
||||
}
|
||||
if (isFountOn && isMixerOn) // both motores are on
|
||||
{
|
||||
if (_mainWindow.startRecipe == 1 && (_mainWindow.Heating == 10 || _mainWindow.cooling == 10 || _mainWindow.pouring == 10))
|
||||
{
|
||||
_mainWindow.unPause = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
await Task.Delay(10);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
54
DaireApplication/Loops/TouchLoop.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using DaireApplication.Views;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DaireApplication.Loops
|
||||
{
|
||||
public class TouchLoop
|
||||
{
|
||||
static void SetBrightness(int value)
|
||||
{
|
||||
//File.WriteAllText("/sys/class/backlight/backlight/brightness", value.ToString());
|
||||
}
|
||||
public static async void Touch(MainWindow _mainWindow)
|
||||
{
|
||||
static void WatchInput(int bright, MainWindow _mainWindow)
|
||||
{
|
||||
|
||||
string inputDevice = "/dev/input/event1"; // adjust based on your touch device
|
||||
using (FileStream fs = new FileStream(inputDevice, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
byte[] buffer = new byte[24];
|
||||
|
||||
fs.Read(buffer, 0, buffer.Length);
|
||||
_mainWindow.lastActivity = DateTime.Now;
|
||||
SetBrightness(bright); // Restore brightness if touch
|
||||
}
|
||||
}
|
||||
|
||||
var screenData = _mainWindow._screeen.ReadScreens()?[0];
|
||||
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
screenData = _mainWindow._screeen.ReadScreens()?[0];
|
||||
int brightnessValue = (int)((screenData.brightness) / 100.0 * 255);
|
||||
MainWindow.isOff = false;
|
||||
//WatchInput(brightnessValue, _mainWindow);
|
||||
Thread.Sleep(200);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
504
DaireApplication/Loops/serialThreadLoop.cs
Normal file
@@ -0,0 +1,504 @@
|
||||
using Avalonia.Threading;
|
||||
using AvaloniaApplication1.ViewModels;
|
||||
using DaireApplication.DataBase;
|
||||
using DaireApplication.ViewModels;
|
||||
using DaireApplication.Views;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DaireApplication.Loops
|
||||
{
|
||||
public class SerialRequest
|
||||
{
|
||||
public enum RequestType { Read, Write }
|
||||
public RequestType Type { get; set; }
|
||||
public byte[] Data { get; set; }
|
||||
public int ExpectedLength { get; set; }
|
||||
public TaskCompletionSource<byte[]> Completion { get; set; } = new();
|
||||
}
|
||||
|
||||
public class serialThreadLoop
|
||||
{
|
||||
private static readonly ConcurrentQueue<SerialRequest> writeQueue = new();
|
||||
private static readonly ConcurrentQueue<SerialRequest> readQueue = new();
|
||||
private static bool keepSendingRunning = false;
|
||||
|
||||
public static Task<byte[]> EnqueueWrite(byte[] data, int expectedLength)
|
||||
{
|
||||
var req = new SerialRequest { Type = SerialRequest.RequestType.Write, Data = data, ExpectedLength = expectedLength };
|
||||
writeQueue.Enqueue(req);
|
||||
return req.Completion.Task;
|
||||
}
|
||||
public static Task<byte[]> EnqueueRead(byte[] data, int expectedLength)
|
||||
{
|
||||
var req = new SerialRequest { Type = SerialRequest.RequestType.Read, Data = data, ExpectedLength = expectedLength };
|
||||
readQueue.Enqueue(req);
|
||||
return req.Completion.Task;
|
||||
}
|
||||
|
||||
public static async void SendViaSerial(MainWindow _mainWindow)
|
||||
{
|
||||
try
|
||||
{
|
||||
//Debug.WriteLine("SendViaSerial started");
|
||||
// Start the keepSending background task if not already running
|
||||
if (!keepSendingRunning)
|
||||
{
|
||||
//Debug.WriteLine("Starting KeepSendingLoop");
|
||||
keepSendingRunning = true;
|
||||
_ = Task.Run(() => KeepSendingLoop(_mainWindow));
|
||||
}
|
||||
|
||||
List<float> values = new List<float>();
|
||||
while (_mainWindow.serialThreadRunning)
|
||||
{
|
||||
//Debug.WriteLine($"SendViaSerial loop iteration - Port status: {(_mainWindow._port?.IsOpen ?? false)}");
|
||||
if (_mainWindow._port != null && _mainWindow._port.IsOpen)
|
||||
{
|
||||
if (_mainWindow.reSendHolding)
|
||||
{
|
||||
values.Clear();
|
||||
_mainWindow._configrations = _mainWindow._config.ReadConfigrations();
|
||||
values.Add(_mainWindow.holdingRegister.resetError);
|
||||
values.Add(_mainWindow.holdingRegister.hvOut);
|
||||
values.Add(_mainWindow.holdingRegister.lvOut);
|
||||
values.Add(_mainWindow.holdingRegister.motor);
|
||||
values.Add(_mainWindow.holdingRegister.setTemp1);
|
||||
values.Add(_mainWindow.holdingRegister.setTemp2);
|
||||
values.Add(_mainWindow.holdingRegister.setTemp3);
|
||||
values.Add(_mainWindow.holdingRegister.setTemp4);
|
||||
values.Add((int)(_mainWindow._configrations[0].i_neut * 10));
|
||||
values.Add((int)(_mainWindow._configrations[0].i_mot1 * 10));
|
||||
values.Add((int)(_mainWindow._configrations[0].i_mot2 * 10));
|
||||
foreach (var item in _mainWindow._configrations)
|
||||
{
|
||||
values.Add(item.Max * 10);
|
||||
values.Add(item.Min * 10);
|
||||
values.Add(ConvertToDecimal(item.H_out.ToList()));
|
||||
values.Add(ConvertToDecimal(item.FC_out.ToList()));
|
||||
values.Add(ConvertToDecimal(item.SC_out.ToList()));
|
||||
values.Add(item.FC_Threshold * 10);
|
||||
values.Add(item.HeatConRange * 10);
|
||||
values.Add(item.kp);
|
||||
values.Add(item.ki);
|
||||
values.Add(item.kd);
|
||||
values.Add(item.kl);
|
||||
}
|
||||
_mainWindow._port.DiscardInBuffer();
|
||||
_mainWindow._port.DiscardOutBuffer();
|
||||
byte[] requstConfig = await _mainWindow._modBusMaster.WriteMultipleRegisters(0, values.ToArray());
|
||||
await EnqueueWrite(requstConfig, 7);
|
||||
_mainWindow.reSendHolding = false;
|
||||
}
|
||||
if (_mainWindow.sendConfig)
|
||||
{
|
||||
values.Clear();
|
||||
_mainWindow._configrations = _mainWindow._config.ReadConfigrations();
|
||||
if (!_mainWindow.dontResetOutPuts)
|
||||
{
|
||||
values.Add(0);
|
||||
values.Add(0);
|
||||
values.Add(0);
|
||||
values.Add(-10000);
|
||||
values.Add(-10000);
|
||||
values.Add(-10000);
|
||||
values.Add(-10000);
|
||||
}
|
||||
values.Add((int)(_mainWindow._configrations[0].i_neut * 10));
|
||||
values.Add((int)(_mainWindow._configrations[0].i_mot1 * 10));
|
||||
values.Add((int)(_mainWindow._configrations[0].i_mot2 * 10));
|
||||
foreach (var item in _mainWindow._configrations)
|
||||
{
|
||||
values.Add(item.Max * 10);
|
||||
values.Add(item.Min * 10);
|
||||
values.Add(ConvertToDecimal(item.H_out.ToList()));
|
||||
values.Add(ConvertToDecimal(item.FC_out.ToList()));
|
||||
values.Add(ConvertToDecimal(item.SC_out.ToList()));
|
||||
values.Add(item.FC_Threshold * 10);
|
||||
values.Add(item.HeatConRange * 10);
|
||||
values.Add(item.kp);
|
||||
values.Add(item.ki);
|
||||
values.Add(item.kd);
|
||||
values.Add(item.kl);
|
||||
}
|
||||
|
||||
byte[] requstConfig = await _mainWindow._modBusMaster.WriteMultipleRegisters(_mainWindow.dontResetOutPuts ? (ushort)8 : (ushort)1, values.ToArray());
|
||||
await EnqueueWrite(requstConfig, 7);
|
||||
_mainWindow.sendConfig = false;
|
||||
_mainWindow.dontResetOutPuts = false;
|
||||
}
|
||||
if (_mainWindow.restBoard)
|
||||
{
|
||||
_mainWindow.holdingRegister.hvOut = 0;
|
||||
_mainWindow.holdingRegister.lvOut = 0;
|
||||
_mainWindow.holdingRegister.motor = 0;
|
||||
_mainWindow.holdingRegister.setTemp1 = -10000;
|
||||
_mainWindow.holdingRegister.setTemp2 = -10000;
|
||||
_mainWindow.holdingRegister.setTemp3 = -10000;
|
||||
_mainWindow.holdingRegister.setTemp4 = -10000;
|
||||
|
||||
// Send reset data directly without using the async pattern
|
||||
List<float> resetValues = new List<float>();
|
||||
resetValues.Add(_mainWindow.holdingRegister.resetError);
|
||||
resetValues.Add(_mainWindow.holdingRegister.hvOut);
|
||||
resetValues.Add(_mainWindow.holdingRegister.lvOut);
|
||||
resetValues.Add(_mainWindow.holdingRegister.motor);
|
||||
resetValues.Add(_mainWindow.holdingRegister.setTemp1);
|
||||
resetValues.Add(_mainWindow.holdingRegister.setTemp2);
|
||||
resetValues.Add(_mainWindow.holdingRegister.setTemp3);
|
||||
resetValues.Add(_mainWindow.holdingRegister.setTemp4);
|
||||
|
||||
byte[] resetRequest = await _mainWindow._modBusMaster.WriteMultipleRegisters(0, resetValues.ToArray());
|
||||
await EnqueueWrite(resetRequest, 7);
|
||||
|
||||
_mainWindow.restBoard = false;
|
||||
}
|
||||
// Check if there's a pending write request
|
||||
if (_mainWindow._writeCompletionSource?.Task.Status == TaskStatus.WaitingForActivation)
|
||||
{
|
||||
List<float> writingValues = new List<float>();
|
||||
writingValues.Add(_mainWindow.holdingRegister.resetError);
|
||||
writingValues.Add(_mainWindow.holdingRegister.hvOut);
|
||||
writingValues.Add(_mainWindow.holdingRegister.lvOut);
|
||||
writingValues.Add(_mainWindow.holdingRegister.motor);
|
||||
writingValues.Add(_mainWindow.holdingRegister.setTemp1);
|
||||
writingValues.Add(_mainWindow.holdingRegister.setTemp2);
|
||||
writingValues.Add(_mainWindow.holdingRegister.setTemp3);
|
||||
writingValues.Add(_mainWindow.holdingRegister.setTemp4);
|
||||
byte[] requstConfig = await _mainWindow._modBusMaster.WriteMultipleRegisters(0, writingValues.ToArray());
|
||||
var result = await EnqueueWrite(requstConfig, 7);
|
||||
// Signal completion
|
||||
bool success = result.Length != 1 || result[0] != 0xFF;
|
||||
_mainWindow.SetWriteComplete(success);
|
||||
}
|
||||
var requstReadingInputs = await _mainWindow._modBusMaster.ReadInputRegisters(0, 18);
|
||||
await EnqueueRead(requstReadingInputs, 41);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static async Task KeepSendingLoop(MainWindow _mainWindow)
|
||||
{
|
||||
//Debug.WriteLine("KeepSendingLoop started");
|
||||
var startTime = DateTime.Now;
|
||||
int intervalMs = _mainWindow.screenData.sendingTime;
|
||||
int requestCount = 0;
|
||||
|
||||
while (_mainWindow.serialThreadRunning)
|
||||
{
|
||||
try
|
||||
{
|
||||
_mainWindow.screenData = _mainWindow._screeen.ReadScreens()[0];
|
||||
//Debug.WriteLine($"KeepSendingLoop iteration - Port status: {(_mainWindow._port?.IsOpen ?? false)}, SendingTime: {_mainWindow.screenData.sendingTime}ms");
|
||||
|
||||
// Skip if port is not valid
|
||||
if (_mainWindow._port == null || !_mainWindow._port.IsOpen)
|
||||
{
|
||||
//Debug.WriteLine("Port not valid, waiting...");
|
||||
await Task.Delay(100); // Wait a bit before checking again
|
||||
continue;
|
||||
}
|
||||
|
||||
var scheduledTime = startTime.AddMilliseconds(requestCount * intervalMs);
|
||||
var now = DateTime.Now;
|
||||
var waitTime = (scheduledTime - now).TotalMilliseconds;
|
||||
if (waitTime > 0)
|
||||
await Task.Delay((int)waitTime);
|
||||
|
||||
SerialRequest req = null;
|
||||
if (!writeQueue.TryPeek(out req))
|
||||
readQueue.TryPeek(out req);
|
||||
|
||||
if (req != null)
|
||||
{
|
||||
var requestStart = DateTime.Now;
|
||||
var response = await keepSendingScenario(_mainWindow, req.Data, req.ExpectedLength,_mainWindow.screenData.sendingTime);
|
||||
var requestEnd = DateTime.Now;
|
||||
var requestElapsed = (requestEnd - requestStart).TotalMilliseconds;
|
||||
if (response.Length != 1 || response[0] != 0xFF)
|
||||
{
|
||||
//Debug.WriteLine($"SUCCESS: Total time for request: {requestElapsed} ms");
|
||||
if (req.Type == SerialRequest.RequestType.Read)
|
||||
{
|
||||
_mainWindow.inputesResponse = response;
|
||||
}
|
||||
req.Completion.SetResult(response);
|
||||
}
|
||||
else // failed after retries or timeout
|
||||
{
|
||||
//Debug.WriteLine($"FAILED: Total time for request: {requestElapsed} ms");
|
||||
req.Completion.SetResult(response); // set failure result
|
||||
}
|
||||
if (req.Type == SerialRequest.RequestType.Write)
|
||||
writeQueue.TryDequeue(out _);
|
||||
else
|
||||
readQueue.TryDequeue(out _);
|
||||
}
|
||||
|
||||
requestCount++;
|
||||
// If we are behind schedule, catch up
|
||||
if ((DateTime.Now - startTime).TotalMilliseconds > requestCount * intervalMs)
|
||||
requestCount = (int)((DateTime.Now - startTime).TotalMilliseconds / intervalMs);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//Debug.WriteLine($"Error in KeepSendingLoop: {ex.Message}");
|
||||
await Task.Delay(100); // Wait a bit before retrying
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<byte[]> keepSendingScenario(MainWindow _mainWindow, byte[] request, int expectedLength, int interval)
|
||||
{
|
||||
// Enforce minimum interval between packets
|
||||
using var cts = new CancellationTokenSource();
|
||||
int SENDING_INTERVAL = interval; // Minimum interval between sends
|
||||
|
||||
var now = DateTime.Now;
|
||||
var elapsed = (now - _mainWindow._lastPacketSendTime).TotalMilliseconds;
|
||||
if (elapsed < _mainWindow.screenData.sendingTime)
|
||||
{
|
||||
await Task.Delay((int)(SENDING_INTERVAL - elapsed));
|
||||
}
|
||||
_mainWindow._lastPacketSendTime = DateTime.Now;
|
||||
|
||||
//Debug.WriteLine("keepSending started");
|
||||
|
||||
// Calculate 4 character delay based on baud rate
|
||||
double fourCharDelay = (1.0 / _mainWindow.screenData.boundRate) * 44000;
|
||||
int noResponseRetryCount = 0;
|
||||
const int MAX_NO_RESPONSE_RETRIES = 3; // Try 3 times, once per second
|
||||
const int NO_RESPONSE_TIMEOUT = 1000; // 1 second between no-response retries
|
||||
const int TOTAL_INVALID_RETRY_TIME = 3000; // 3 seconds total for invalid responses
|
||||
|
||||
var startTime = DateTime.Now;
|
||||
var lastSendTime = DateTime.Now;
|
||||
var lastValidResponseTime = DateTime.Now;
|
||||
bool hadValidResponse = false;
|
||||
|
||||
while ((DateTime.Now - startTime).TotalMilliseconds < TOTAL_INVALID_RETRY_TIME)
|
||||
{
|
||||
// Calculate time since last send
|
||||
var timeSinceLastSend = (DateTime.Now - lastSendTime).TotalMilliseconds;
|
||||
var timeSinceLastValidResponse = (DateTime.Now - lastValidResponseTime).TotalMilliseconds;
|
||||
|
||||
// Check for communication timeout
|
||||
if (timeSinceLastValidResponse >= TOTAL_INVALID_RETRY_TIME && !hadValidResponse)
|
||||
{
|
||||
//Debug.WriteLine("No valid response received within 3 seconds");
|
||||
if (!MainWindow.errors.Any(x => x.Condition == Error.GridCondition.NoBoardCom))
|
||||
{
|
||||
MainWindow.errors.Add(new Error
|
||||
{
|
||||
errorDate = DateTime.Now,
|
||||
Condition = Error.GridCondition.NoBoardCom
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// For no response case, check frequently for response
|
||||
if (noResponseRetryCount > 0 && timeSinceLastSend < NO_RESPONSE_TIMEOUT)
|
||||
{
|
||||
// Check for response every 10ms
|
||||
if (_mainWindow._port != null && _mainWindow._port.IsOpen)
|
||||
{
|
||||
if (_mainWindow._port.BytesToRead >= expectedLength)
|
||||
{
|
||||
// Wait 4-char delay when we have enough bytes
|
||||
await Task.Delay((int)fourCharDelay);
|
||||
var response = await TryReadOnce(_mainWindow, expectedLength, cts.Token);
|
||||
//Debug.WriteLine($"Response received during wait after {timeSinceLastSend}ms");
|
||||
|
||||
if (response.Length == expectedLength && IsValidCrc(response))
|
||||
{
|
||||
hadValidResponse = true;
|
||||
lastValidResponseTime = DateTime.Now; // Reset valid response timer
|
||||
var err = MainWindow.errors.FirstOrDefault(x => x.Condition == Error.GridCondition.NoBoardCom);
|
||||
if (err != null) err.isDeleted = true;
|
||||
|
||||
// For valid response, still respect minimum interval
|
||||
//if (timeSinceLastSend < SENDING_INTERVAL)
|
||||
//{
|
||||
// var remainingTime = SENDING_INTERVAL - timeSinceLastSend;
|
||||
// Debug.WriteLine($"Valid response received before {SENDING_INTERVAL}ms, waiting {remainingTime}ms");
|
||||
// await Task.Delay((int)remainingTime);
|
||||
//}
|
||||
return response;
|
||||
}
|
||||
|
||||
// For any response (even invalid), increment retry count and continue immediately
|
||||
noResponseRetryCount++;
|
||||
if (noResponseRetryCount >= MAX_NO_RESPONSE_RETRIES)
|
||||
{
|
||||
//Debug.WriteLine("Max retries exceeded");
|
||||
if (!MainWindow.errors.Any(x => x.Condition == Error.GridCondition.NoBoardCom))
|
||||
{
|
||||
MainWindow.errors.Add(new Error
|
||||
{
|
||||
errorDate = DateTime.Now,
|
||||
Condition = Error.GridCondition.NoBoardCom
|
||||
});
|
||||
}
|
||||
return new byte[] { 0xFF };
|
||||
}
|
||||
|
||||
// Break wait and send next retry immediately
|
||||
lastSendTime = DateTime.Now.AddMilliseconds(-NO_RESPONSE_TIMEOUT); // Force immediate retry
|
||||
break;
|
||||
}
|
||||
/*await Task.Delay(10);*/ // Small delay between checks
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// For invalid response case, wait minimum interval between retries
|
||||
if (timeSinceLastSend < SENDING_INTERVAL)
|
||||
{
|
||||
await Task.Delay(1); // Minimal delay to prevent tight loop
|
||||
continue;
|
||||
}
|
||||
|
||||
// Send the request
|
||||
_mainWindow._port.Write(request, 0, request.Length);
|
||||
lastSendTime = DateTime.Now;
|
||||
//Debug.WriteLine($"Sent request at {lastSendTime:HH:mm:ss.fffffff}");
|
||||
|
||||
// Wait 4-char delay after sending
|
||||
await Task.Delay((int)fourCharDelay);
|
||||
|
||||
// Try to read response
|
||||
if (_mainWindow._port != null && _mainWindow._port.IsOpen && _mainWindow._port.BytesToRead >= expectedLength)
|
||||
{
|
||||
// Wait another 4-char delay when we have enough bytes
|
||||
await Task.Delay((int)fourCharDelay);
|
||||
var response = await TryReadOnce(_mainWindow, expectedLength, cts.Token);
|
||||
|
||||
// Handle valid response
|
||||
if (response.Length >= expectedLength && IsValidCrc(response))
|
||||
{
|
||||
hadValidResponse = true;
|
||||
lastValidResponseTime = DateTime.Now; // Reset valid response timer
|
||||
var err = MainWindow.errors.FirstOrDefault(x => x.Condition == Error.GridCondition.NoBoardCom);
|
||||
if (err != null) err.isDeleted = true;
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle invalid/no response
|
||||
noResponseRetryCount++;
|
||||
//Debug.WriteLine($"Invalid/No response, attempt {noResponseRetryCount} of {MAX_NO_RESPONSE_RETRIES}");
|
||||
if (noResponseRetryCount >= MAX_NO_RESPONSE_RETRIES)
|
||||
{
|
||||
//Debug.WriteLine("Max retries exceeded");
|
||||
if (!MainWindow.errors.Any(x => x.Condition == Error.GridCondition.NoBoardCom))
|
||||
{
|
||||
MainWindow.errors.Add(new Error
|
||||
{
|
||||
errorDate = DateTime.Now,
|
||||
Condition = Error.GridCondition.NoBoardCom
|
||||
});
|
||||
}
|
||||
return new byte[] { 0xFF };
|
||||
}
|
||||
}
|
||||
|
||||
return new byte[] { 0xFF };
|
||||
}
|
||||
|
||||
private static async Task<byte[]> TryReadOnce(MainWindow _mainWindow, int expectedLength, CancellationToken token)
|
||||
{
|
||||
var buffer = new List<byte>();
|
||||
var startTime = DateTime.UtcNow;
|
||||
var timeout = 3000;
|
||||
while ((DateTime.UtcNow - startTime).TotalMilliseconds < timeout)
|
||||
{
|
||||
token.ThrowIfCancellationRequested();
|
||||
if (_mainWindow._port != null && _mainWindow._port.IsOpen)
|
||||
{
|
||||
int available = _mainWindow._port.BytesToRead;
|
||||
if (available > 0)
|
||||
{
|
||||
byte[] temp = new byte[available];
|
||||
_mainWindow._port.Read(temp, 0, available);
|
||||
buffer.AddRange(temp);
|
||||
if (buffer.Count >= 3)
|
||||
{
|
||||
var response = buffer.ToArray();
|
||||
if (response.Length < expectedLength)
|
||||
{
|
||||
//Debug.WriteLine($"Invalid response length: got {response.Length}, expected {expectedLength}");
|
||||
return new byte[] { 0xFF };
|
||||
}
|
||||
if (!IsValidCrc(response))
|
||||
{
|
||||
//Debug.WriteLine("Invalid CRC in response");
|
||||
return new byte[] { 0xFF };
|
||||
}
|
||||
var err = MainWindow.errors.FirstOrDefault(x => x.Condition == Error.GridCondition.NoBoardCom);
|
||||
if (err != null) err.isDeleted = true;
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
||||
await Task.Delay(1);
|
||||
}
|
||||
//Debug.WriteLine("Response timeout");
|
||||
return new byte[] { 0xFF };
|
||||
}
|
||||
|
||||
private static bool IsValidCrc(byte[] data)
|
||||
{
|
||||
if (data.Length < 3) return false;
|
||||
ushort calculated = ComputeCRC(data.AsSpan(0, data.Length - 2));
|
||||
ushort received = (ushort)(data[^2] | (data[^1] << 8));
|
||||
return calculated == received;
|
||||
}
|
||||
private static ushort ComputeCRC(ReadOnlySpan<byte> data)
|
||||
{
|
||||
ushort crc = 0xFFFF;
|
||||
foreach (var b in data)
|
||||
{
|
||||
crc ^= b;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if ((crc & 0x0001) != 0)
|
||||
{
|
||||
crc >>= 1;
|
||||
crc ^= 0xA001;
|
||||
}
|
||||
else
|
||||
{
|
||||
crc >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
static int ConvertToDecimal(List<int> bitPositions)
|
||||
{
|
||||
int result = 0;
|
||||
if (bitPositions.Count() == 1 && bitPositions[0] == -1)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
foreach (var pos in bitPositions)
|
||||
{
|
||||
if (pos is >= 0 and < 16)
|
||||
result |= 1 << pos;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
247
DaireApplication/Pedal_Based_Fountain_Control_Implementation.md
Normal file
@@ -0,0 +1,247 @@
|
||||
# Pedal-Based Fountain Control Implementation
|
||||
|
||||
## Overview
|
||||
|
||||
This implementation replaces the previous automatic fountain control with a **direct pedal-based control system**. When the pedal is in AUTO mode, the chocolate fountain directly follows the pedal state - ON when pedal is active, OFF when pedal is inactive.
|
||||
|
||||
## ✅ Expected Behavior
|
||||
|
||||
When pedal is in **AUTO mode**:
|
||||
- **Pedal ON** (pedalState = 0) → **Chocolate ON** (fountain flows)
|
||||
- **Pedal OFF** (pedalState = 1) → **Chocolate OFF** (fountain stops)
|
||||
- **No blinking/flashing** of the Chocolate button
|
||||
- **Clean alternating ON/OFF** based on pedal timing settings
|
||||
|
||||
## 🔧 Implementation Details
|
||||
|
||||
### 1. Direct Fountain Control Logic
|
||||
|
||||
Located in the main monitoring loop (`pedalMotor == 1` section):
|
||||
|
||||
```csharp
|
||||
else if (pedalMotor == 1) // auto Pedal
|
||||
{
|
||||
// Set auto mode flag
|
||||
isPedalAutoMode = true;
|
||||
|
||||
// Direct fountain control based on pedal state
|
||||
var fount = _mapping.Find(x => x.Name.ToLower() == "Helix".ToLower());
|
||||
if (fount != null && fount.BitNumbers.Count > 0)
|
||||
{
|
||||
if (pedalState == 0) // Pedal ON - Turn fountain ON
|
||||
{
|
||||
foreach (var bit in fount.BitNumbers)
|
||||
{
|
||||
holdingRegister.motor |= (ushort)(1 << bit); // Set the motor bit ON
|
||||
}
|
||||
isFountainMotorOn = true;
|
||||
startFountainMotor = 1;
|
||||
sendComFountainMotor = 1;
|
||||
startFountainMotorFlashing = -1; // No flashing
|
||||
// ... UI updates and hardware commands
|
||||
}
|
||||
else if (pedalState == 1) // Pedal OFF - Turn fountain OFF
|
||||
{
|
||||
foreach (var bit in fount.BitNumbers)
|
||||
{
|
||||
holdingRegister.motor &= (ushort)~(1 << bit); // Clear the motor bit OFF
|
||||
}
|
||||
isFountainMotorOn = false;
|
||||
startFountainMotor = 0;
|
||||
sendComFountainMotor = 0;
|
||||
startFountainMotorFlashing = -1; // No flashing
|
||||
// ... UI updates and hardware commands
|
||||
}
|
||||
}
|
||||
|
||||
// Handle pedal timing (alternating ON/OFF based on recipe settings)
|
||||
// ... timer management logic
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Pedal Timing Configuration
|
||||
|
||||
From the UI, users can configure:
|
||||
- **PEDAL OFF TIME**: Duration fountain stays OFF (e.g., 1 unit)
|
||||
- **PEDAL ON TIME**: Duration fountain stays ON (e.g., 2 seconds)
|
||||
|
||||
The system automatically alternates between these states using timers.
|
||||
|
||||
### 3. UI Feedback
|
||||
|
||||
#### Chocolate Button State
|
||||
- **ON**: Shows "ON" with active color (magenta underline)
|
||||
- **OFF**: Shows "OFF" with passive color (gray)
|
||||
- **No flashing/blinking** during automatic operation
|
||||
|
||||
#### Temperature Display
|
||||
When fountain is ON, the UI also shows:
|
||||
- Current Temp: [actual temperature]
|
||||
- Target Temp: [target temperature]
|
||||
|
||||
### 4. Manual Override
|
||||
|
||||
When user manually clicks the fountain button:
|
||||
- **Resets pedal auto mode** (`isPedalAutoMode = false`)
|
||||
- **Stops all pedal timers**
|
||||
- **Switches to manual mode** (`pedalMotor = -1`)
|
||||
- **User gains full manual control**
|
||||
|
||||
### 5. Protection Logic
|
||||
|
||||
#### Fountain Control Protection
|
||||
Normal fountain control logic is disabled when pedal auto mode is active:
|
||||
|
||||
```csharp
|
||||
// Temperature-based control (disabled in pedal auto mode)
|
||||
if (checkFountainTMT_PMT && !isPedalAutoMode)
|
||||
|
||||
// Manual control (disabled in pedal auto mode)
|
||||
if (!checkFountainTMT_PMT && !isPedalAutoMode)
|
||||
|
||||
// Flashing processing (disabled in pedal auto mode)
|
||||
if (startFountainMotorFlashing == 1 && !isPedalAutoMode)
|
||||
```
|
||||
|
||||
#### UI Flashing Protection
|
||||
The InteractiveUILoop prevents button flashing in pedal auto mode:
|
||||
|
||||
```csharp
|
||||
// Only flash when not in pedal auto mode
|
||||
if (_mainWindow.startFountainMotorFlashing == 1 && !_mainWindow.isPedalAutoMode)
|
||||
```
|
||||
|
||||
## 🔄 Control Flow
|
||||
|
||||
1. **User sets pedal to AUTO mode**
|
||||
- Pedal timers start alternating
|
||||
- `isPedalAutoMode = true`
|
||||
|
||||
2. **Pedal timer triggers state change**
|
||||
- `pedalState = 0` (ON) or `pedalState = 1` (OFF)
|
||||
|
||||
3. **Main monitoring loop processes state**
|
||||
- Directly controls fountain motor based on pedal state
|
||||
- Updates UI immediately
|
||||
- Sends hardware commands
|
||||
|
||||
4. **Fountain responds immediately**
|
||||
- ON: Chocolate flows
|
||||
- OFF: Chocolate stops
|
||||
- No delays or intermediate states
|
||||
|
||||
5. **Cycle repeats based on timing settings**
|
||||
- OFF for configured duration
|
||||
- ON for configured duration
|
||||
|
||||
## 🛡️ Safety Features
|
||||
|
||||
1. **Manual Override**: User can always take manual control
|
||||
2. **Timer Cleanup**: Pedal timers are properly stopped when needed
|
||||
3. **State Reset**: Pedal auto mode is reset when starting/stopping recipes
|
||||
4. **No Conflicts**: Other fountain control mechanisms are disabled during pedal auto mode
|
||||
5. **Immediate Response**: No delays or buffering - fountain responds instantly to pedal state
|
||||
|
||||
## 🚫 Previous Logic Removed
|
||||
|
||||
The following complex logic was removed and replaced with direct control:
|
||||
- ❌ Temperature threshold-based fountain control in pedal auto mode
|
||||
- ❌ Automatic fountain control based on second control box
|
||||
- ❌ Complex state management with multiple flags
|
||||
- ❌ Delayed or conditional fountain control
|
||||
- ❌ Multiple control mechanisms that could conflict
|
||||
|
||||
## 📱 User Interface
|
||||
|
||||
### Settings Panel
|
||||
Shows current pedal configuration:
|
||||
- **PEDAL**: AUTO/MANUAL toggle button
|
||||
- **PEDAL OFF TIME**: Adjustable duration (e.g., 1 unit)
|
||||
- **PEDAL ON TIME**: Adjustable duration (e.g., 2 seconds)
|
||||
|
||||
### Fountain Button
|
||||
- **Steady state display** (ON/OFF)
|
||||
- **Color coding**: Active (magenta) / Passive (gray)
|
||||
- **No blinking/flashing** during automatic operation
|
||||
- **Click to override** and take manual control
|
||||
|
||||
## 🧪 Testing Scenarios
|
||||
|
||||
### Scenario 1: Basic Auto Mode Operation
|
||||
1. Set pedal to AUTO mode
|
||||
2. Configure timing (e.g., 2s ON, 1 unit OFF)
|
||||
3. **Expected**: Fountain alternates cleanly between ON/OFF states
|
||||
|
||||
### Scenario 2: Manual Override
|
||||
1. While in auto mode, click fountain button
|
||||
2. **Expected**: Auto mode stops, user gains manual control
|
||||
|
||||
### Scenario 3: Recipe Integration
|
||||
1. Start recipe with pedal in AUTO mode
|
||||
2. Complete all phases
|
||||
3. **Expected**: Fountain follows pedal timing throughout
|
||||
|
||||
### Scenario 4: Visual Feedback
|
||||
1. Observe fountain button during auto operation
|
||||
2. **Expected**: Clean ON/OFF display without blinking
|
||||
|
||||
## 📋 Configuration
|
||||
|
||||
### Pedal Timing Settings
|
||||
- Configured through Settings UI
|
||||
- **PEDAL OFF TIME**: How long fountain stays OFF
|
||||
- **PEDAL ON TIME**: How long fountain stays ON
|
||||
- Values are saved in recipe table
|
||||
|
||||
### Control Mode
|
||||
- **AUTO**: Fountain follows pedal timing automatically
|
||||
- **MANUAL**: User controls fountain manually via button clicks
|
||||
|
||||
## 🔧 Key Improvements
|
||||
|
||||
### Simplified Logic ✅
|
||||
- **Direct control**: Pedal state directly controls fountain
|
||||
- **No intermediate states** or complex decision trees
|
||||
- **Immediate response** with no delays
|
||||
|
||||
### User Experience ✅
|
||||
- **Predictable behavior**: ON when pedal ON, OFF when pedal OFF
|
||||
- **Visual clarity**: Clean state display without blinking
|
||||
- **Easy override**: Click fountain button to take manual control
|
||||
|
||||
### Reliability ✅
|
||||
- **No conflicts**: Other control mechanisms properly disabled
|
||||
- **Clean state management**: Single source of truth for pedal auto mode
|
||||
- **Proper cleanup**: Timers and states reset when needed
|
||||
|
||||
### Performance ✅
|
||||
- **Efficient processing**: Minimal logic overhead
|
||||
- **Instant response**: No waiting or buffering
|
||||
- **Resource management**: Proper timer lifecycle management
|
||||
|
||||
## 📝 Technical Notes
|
||||
|
||||
### Timer Management
|
||||
- `pedalOnTimer`: Controls ON duration
|
||||
- `pedalOffTimer`: Controls OFF duration
|
||||
- Timers are properly disposed when not needed
|
||||
|
||||
### State Variables
|
||||
- `isPedalAutoMode`: Main flag indicating pedal auto mode is active
|
||||
- `pedalState`: Current pedal state (0=ON, 1=OFF, -1=reset)
|
||||
- `pedalMotor`: Pedal mode (1=AUTO, -1=MANUAL)
|
||||
|
||||
### Hardware Control
|
||||
- Direct bit manipulation of `holdingRegister.motor`
|
||||
- Immediate serial communication with hardware
|
||||
- Synchronized UI updates
|
||||
|
||||
## ✅ Requirements Fulfilled
|
||||
|
||||
✅ **Direct pedal control**: Fountain follows pedal state exactly
|
||||
✅ **Timing-based operation**: Uses configured ON/OFF durations
|
||||
✅ **No blinking**: Clean visual feedback without flashing
|
||||
✅ **Manual override**: User can always take control
|
||||
✅ **Proper integration**: Works with existing recipe system
|
||||
✅ **Clean UI**: Professional appearance without distractions
|
||||
✅ **Reliable operation**: No conflicts or unexpected behavior
|
||||
33
DaireApplication/Program.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.ReactiveUI;
|
||||
using AvaloniaApplication1.DataBase;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DaireApplication
|
||||
{
|
||||
internal sealed class Program
|
||||
{
|
||||
// Initialization code. Don't use any Avalonia, third-party APIs or any
|
||||
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
|
||||
// yet and stuff might break.
|
||||
[STAThread]
|
||||
public static void Main(string[] args) => BuildAvaloniaApp()
|
||||
.StartWithClassicDesktopLifetime(args);
|
||||
public static UserTable? currentUser;
|
||||
|
||||
public static int pouringMinTemp = -5;
|
||||
public static int absoluteMaxTemp = 70;
|
||||
public static int absoluteMinTemp = -10;
|
||||
// Avalonia configuration, don't remove; also used by visual designer.
|
||||
public static AppBuilder BuildAvaloniaApp()
|
||||
=> AppBuilder.Configure<App>()
|
||||
.UsePlatformDetect()
|
||||
.WithInterFont()
|
||||
.LogToTrace()
|
||||
.UseReactiveUI();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Any CPU</Platform>
|
||||
<PublishDir>C:\Users\Swb\Desktop\test</PublishDir>
|
||||
<PublishProtocol>FileSystem</PublishProtocol>
|
||||
<_TargetId>Folder</_TargetId>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<SelfContained>true</SelfContained>
|
||||
<PublishSingleFile>false</PublishSingleFile>
|
||||
<PublishReadyToRun>false</PublishReadyToRun>
|
||||
<PublishTrimmed>false</PublishTrimmed>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
225
DaireApplication/Recipe_System_Enhancement_Summary.md
Normal file
@@ -0,0 +1,225 @@
|
||||
# Recipe System Enhancement Summary
|
||||
|
||||
## Overview
|
||||
This document outlines the comprehensive enhancements made to the recipe system in the DaireApplication, implementing proper goal checking, timer initiation, and phase transitions as requested.
|
||||
|
||||
## Key Features Implemented
|
||||
|
||||
### 1. Goal Check and Validation
|
||||
- **Input Validation**: Validates recipe parameters before starting
|
||||
- **Temperature Goal Validation**: Ensures heating, cooling, and pouring goals are reasonable
|
||||
- **Logical Validation**: Verifies cooling goal is less than heating goal
|
||||
- **Real-time Monitoring**: Continuously monitors temperature goals during execution
|
||||
|
||||
### 2. Timer Initiation Logic
|
||||
- **Dual Goal Checking**: Checks both mixer (tank) and chocolate (fountain) heating goals
|
||||
- **Conditional Timer Start**: Only starts timers when both goals are met
|
||||
- **Phase-specific Timers**: Separate timers for heating, cooling, and pouring phases
|
||||
- **Automatic Phase Transitions**: Seamless transitions between phases
|
||||
|
||||
### 3. Temperature Monitoring and Phase Transitions
|
||||
- **Continuous Temperature Tracking**: Monitors chocolate temperature throughout the process
|
||||
- **Cooling Phase Logic**:
|
||||
- If chocolate temperature equals cooling threshold → Shows cooling delay
|
||||
- If chocolate temperature not at cooling threshold → Initiates cooling phase
|
||||
- **Error Handling**: Comprehensive error handling for temperature deviations
|
||||
- **Warning System**: Proactive warnings when temperatures approach limits
|
||||
|
||||
## Implementation Details
|
||||
|
||||
### Enhanced RecipeStartBtn Method
|
||||
```csharp
|
||||
public async void RecipeStartBtn(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
// 1. Initialize and validate recipe parameters
|
||||
if (!await InitializeAndValidateRecipe()) return;
|
||||
|
||||
// 2. Start goal monitoring and phase transitions
|
||||
await StartRecipePhaseMonitoring();
|
||||
|
||||
// 3. Update UI and begin execution
|
||||
}
|
||||
```
|
||||
|
||||
### Goal Checking Methods
|
||||
```csharp
|
||||
// Check if mixer heating goal is reached
|
||||
private async Task<bool> CheckMixerHeatingGoal()
|
||||
{
|
||||
bool goalMet = comTankTemp >= recipeHeatingGoal - 3;
|
||||
// Provides user feedback when goal is reached
|
||||
return goalMet;
|
||||
}
|
||||
|
||||
// Check if chocolate heating goal is reached
|
||||
private async Task<bool> CheckChocolateHeatingGoal()
|
||||
{
|
||||
bool goalMet = comFountainTemp >= recipeHeatingGoal - 3;
|
||||
// Provides user feedback when goal is reached
|
||||
return goalMet;
|
||||
}
|
||||
```
|
||||
|
||||
### Phase Transition Logic
|
||||
```csharp
|
||||
// Handle cooling phase transition based on chocolate temperature
|
||||
private async Task HandleCoolingPhaseTransition(Settings settings)
|
||||
{
|
||||
bool chocolateAtCoolingTemp = Math.Abs(comFountainTemp - recipeCoolingGoal) <= 3;
|
||||
|
||||
if (chocolateAtCoolingTemp && cooling == -1 && Heating == -1)
|
||||
{
|
||||
await ShowCoolingDelay(settings); // Show delay when at target
|
||||
}
|
||||
else if (!chocolateAtCoolingTemp && cooling == -1 && Heating == -1)
|
||||
{
|
||||
await InitiateCoolingPhase(settings); // Start cooling phase
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Enhanced Timer Methods
|
||||
|
||||
### HeatingTimer
|
||||
- **Improved Error Detection**: Better temperature range checking
|
||||
- **Enhanced User Feedback**: Detailed status messages with current temperatures
|
||||
- **Automatic Phase Transition**: Seamlessly transitions to cooling phase
|
||||
- **Warning System**: Proactive warnings for temperature deviations
|
||||
|
||||
### CoolingTimer
|
||||
- **Conditional Phase Logic**: Handles both cooling delay and active cooling
|
||||
- **Temperature Monitoring**: Continuous monitoring of chocolate temperature
|
||||
- **UI Updates**: Shows/hides cooling delay indicators appropriately
|
||||
- **Phase Completion**: Automatic transition to pouring phase
|
||||
|
||||
### PouringTimer
|
||||
- **Recipe Completion**: Handles final phase of recipe execution
|
||||
- **Pedal Control**: Automatically configures pedal based on recipe settings
|
||||
- **Success Feedback**: Provides clear completion status
|
||||
- **Error Handling**: Comprehensive error handling for final phase
|
||||
|
||||
## User Interface Enhancements
|
||||
|
||||
### Real-time Status Updates
|
||||
- **Temperature Display**: Shows current vs target temperatures
|
||||
- **Phase Indicators**: Clear indication of current phase
|
||||
- **Countdown Timers**: Visual countdown for delays
|
||||
- **Error Messages**: Descriptive error messages with temperature details
|
||||
|
||||
### Enhanced Feedback
|
||||
- **Goal Achievement**: Notifications when heating goals are reached
|
||||
- **Phase Transitions**: Clear messages for phase changes
|
||||
- **Completion Status**: Success messages when recipe completes
|
||||
- **Warning System**: Proactive warnings for potential issues
|
||||
|
||||
## Error Handling and Safety
|
||||
|
||||
### Comprehensive Validation
|
||||
- **Recipe Data Validation**: Ensures recipe exists and is valid
|
||||
- **Temperature Goal Validation**: Validates all temperature parameters
|
||||
- **Logical Validation**: Ensures goals make logical sense
|
||||
- **Runtime Validation**: Continuous validation during execution
|
||||
|
||||
### Error Recovery
|
||||
- **Temperature Error Handling**: Handles temperature deviations gracefully
|
||||
- **Timer Error Recovery**: Proper cleanup of timers on errors
|
||||
- **UI State Recovery**: Maintains consistent UI state during errors
|
||||
- **User Feedback**: Clear error messages for troubleshooting
|
||||
|
||||
## Performance Optimizations
|
||||
|
||||
### Asynchronous Operations
|
||||
- **Non-blocking UI**: All operations run asynchronously
|
||||
- **Efficient Monitoring**: Optimized temperature monitoring loops
|
||||
- **Resource Management**: Proper timer cleanup and resource disposal
|
||||
- **Memory Management**: Efficient memory usage for long-running operations
|
||||
|
||||
### Timer Management
|
||||
- **Conditional Timer Creation**: Only creates timers when needed
|
||||
- **Proper Cleanup**: Ensures all timers are properly disposed
|
||||
- **State Management**: Maintains consistent timer states
|
||||
- **Error Recovery**: Handles timer failures gracefully
|
||||
|
||||
## Benefits of the Enhanced System
|
||||
|
||||
### 1. Improved Reliability
|
||||
- **Goal Validation**: Prevents invalid recipe execution
|
||||
- **Error Detection**: Early detection of temperature issues
|
||||
- **Automatic Recovery**: Self-healing from minor issues
|
||||
- **Consistent Behavior**: Predictable phase transitions
|
||||
|
||||
### 2. Better User Experience
|
||||
- **Clear Feedback**: Users always know what's happening
|
||||
- **Real-time Updates**: Live temperature and status information
|
||||
- **Intuitive Flow**: Logical progression through phases
|
||||
- **Error Clarity**: Clear error messages for troubleshooting
|
||||
|
||||
### 3. Enhanced Safety
|
||||
- **Temperature Monitoring**: Continuous safety monitoring
|
||||
- **Automatic Stops**: Stops on critical temperature deviations
|
||||
- **Validation**: Prevents dangerous recipe configurations
|
||||
- **Recovery**: Graceful handling of unexpected conditions
|
||||
|
||||
### 4. Maintainability
|
||||
- **Modular Design**: Clear separation of concerns
|
||||
- **Comprehensive Documentation**: Well-documented methods
|
||||
- **Error Handling**: Robust error handling throughout
|
||||
- **Code Organization**: Logical method organization
|
||||
|
||||
## Usage Instructions
|
||||
|
||||
### Starting a Recipe
|
||||
1. **Select Recipe**: Choose a valid recipe with proper temperature goals
|
||||
2. **Click Start**: Click "START RECIPE" button
|
||||
3. **Monitor Progress**: Watch real-time temperature and phase updates
|
||||
4. **Handle Errors**: Respond to any error messages that appear
|
||||
|
||||
### Understanding Phases
|
||||
1. **Heating Phase**: Waits for both mixer and chocolate to reach heating goal
|
||||
2. **Cooling Phase**: Either shows delay (if at target) or actively cools
|
||||
3. **Pouring Phase**: Final phase with temperature monitoring
|
||||
4. **Completion**: Recipe finishes and prepares for pouring
|
||||
|
||||
### Error Handling
|
||||
- **Temperature Errors**: Check temperature sensors and heating systems
|
||||
- **Validation Errors**: Verify recipe configuration
|
||||
- **Timer Errors**: Restart recipe if timers fail
|
||||
- **Phase Errors**: Check phase transition conditions
|
||||
|
||||
## Technical Specifications
|
||||
|
||||
### Temperature Tolerances
|
||||
- **Goal Checking**: ±3°C tolerance for goal achievement
|
||||
- **Error Limits**: Configurable via `screenData.errorLimit`
|
||||
- **Warning Limits**: Configurable via `screenData.warningLimit`
|
||||
|
||||
### Timer Intervals
|
||||
- **Monitoring Frequency**: 1 second intervals for temperature checking
|
||||
- **UI Updates**: Real-time UI updates via Dispatcher
|
||||
- **Phase Transitions**: Immediate phase transitions when conditions are met
|
||||
|
||||
### Memory Management
|
||||
- **Timer Cleanup**: Automatic cleanup of completed timers
|
||||
- **Resource Disposal**: Proper disposal of all resources
|
||||
- **State Reset**: Complete state reset on recipe stop
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
### Potential Improvements
|
||||
1. **Recipe Templates**: Pre-configured recipe templates
|
||||
2. **Advanced Monitoring**: Additional sensor monitoring
|
||||
3. **Data Logging**: Recipe execution logging
|
||||
4. **Remote Monitoring**: Remote recipe monitoring capabilities
|
||||
5. **Machine Learning**: Predictive temperature control
|
||||
|
||||
### Scalability Considerations
|
||||
1. **Multiple Recipes**: Support for concurrent recipe execution
|
||||
2. **Advanced Phases**: Additional recipe phases
|
||||
3. **Custom Validations**: User-defined validation rules
|
||||
4. **Integration**: Integration with external systems
|
||||
|
||||
## Conclusion
|
||||
|
||||
The enhanced recipe system provides a robust, reliable, and user-friendly solution for chocolate tempering operations. With comprehensive goal checking, intelligent phase transitions, and extensive error handling, the system ensures consistent, high-quality results while providing clear feedback to operators.
|
||||
|
||||
The modular design and comprehensive documentation make the system maintainable and extensible for future enhancements. The asynchronous architecture ensures responsive user interface while maintaining system reliability and safety.
|
||||
217
DaireApplication/Temperature_Error_Fix_Summary.md
Normal file
@@ -0,0 +1,217 @@
|
||||
# Temperature Error Fix Summary
|
||||
|
||||
## Problem Analysis
|
||||
|
||||
### Issue Identified
|
||||
The system was incorrectly showing "Temperature Error!!" popup during the heating phase when temperatures were **above** the heating goal. This prevented the system from properly transitioning to the cooling phase.
|
||||
|
||||
### Root Cause
|
||||
The temperature error detection logic was using a **symmetric range** (±2°C around the target) for all phases, which is incorrect:
|
||||
|
||||
- **Heating Phase**: Should only error if temperature is **below** the goal
|
||||
- **Cooling Phase**: Should only error if temperature is **above** the goal
|
||||
- **Pouring Phase**: Should error if temperature is outside the acceptable range
|
||||
|
||||
### Example from Image
|
||||
- **Current Temperature**: 51.0°C
|
||||
- **Heating Goal**: 46°C
|
||||
- **Error Limit**: 2°C
|
||||
- **Old Logic**: Acceptable range = 44°C to 48°C ❌
|
||||
- **New Logic**: Acceptable range = 46°C and above ✅
|
||||
|
||||
## Fixes Implemented
|
||||
|
||||
### 1. HeatingTimer - Fixed Temperature Error Logic
|
||||
|
||||
**Before:**
|
||||
```csharp
|
||||
// Symmetric range check (incorrect for heating)
|
||||
bool tempInRange = (comFountainTemp * 10 >= (recipeHeatingGoal * 10) - (screenData.errorLimit * 10)) &&
|
||||
(comFountainTemp * 10 <= (recipeHeatingGoal * 10) + (screenData.errorLimit * 10));
|
||||
```
|
||||
|
||||
**After:**
|
||||
```csharp
|
||||
// Only check if temperature is too low (correct for heating)
|
||||
bool tempTooLow = comFountainTemp < (recipeHeatingGoal - screenData.errorLimit);
|
||||
```
|
||||
|
||||
**Logic:**
|
||||
- ✅ **Temperatures above goal**: Acceptable during heating
|
||||
- ❌ **Temperatures below goal**: Show error
|
||||
- ✅ **Goal achieved**: Proceed to cooling phase
|
||||
|
||||
### 2. CoolingTimer - Fixed Temperature Error Logic
|
||||
|
||||
**Before:**
|
||||
```csharp
|
||||
// Symmetric range check (incorrect for cooling)
|
||||
bool tempInRange = (comFountainTemp * 10 >= (recipeCoolingGoal * 10) - (screenData.errorLimit * 10)) &&
|
||||
(comFountainTemp * 10 <= (recipeCoolingGoal * 10) + (screenData.errorLimit * 10));
|
||||
```
|
||||
|
||||
**After:**
|
||||
```csharp
|
||||
// Only check if temperature is too high (correct for cooling)
|
||||
bool tempTooHigh = comFountainTemp > (recipeCoolingGoal + screenData.errorLimit);
|
||||
```
|
||||
|
||||
**Logic:**
|
||||
- ✅ **Temperatures below goal**: Acceptable during cooling
|
||||
- ❌ **Temperatures above goal**: Show error
|
||||
- ✅ **Goal achieved**: Proceed to pouring phase
|
||||
|
||||
### 3. PouringTimer - Maintained Correct Logic
|
||||
|
||||
**Before & After:**
|
||||
```csharp
|
||||
// Symmetric range check (correct for pouring)
|
||||
bool tempInRange = (comFountainTemp >= (recipePouringGoal - screenData.errorLimit)) &&
|
||||
(comFountainTemp <= (recipePouringGoal + screenData.errorLimit));
|
||||
```
|
||||
|
||||
**Logic:**
|
||||
- ✅ **Temperatures within range**: Acceptable for pouring
|
||||
- ❌ **Temperatures outside range**: Show error
|
||||
- ✅ **Goal achieved**: Recipe completed
|
||||
|
||||
### 4. Goal Checking Methods - Updated Logic
|
||||
|
||||
**Before:**
|
||||
```csharp
|
||||
// Using 3°C tolerance (too permissive)
|
||||
bool goalMet = comFountainTemp >= recipeHeatingGoal - 3;
|
||||
```
|
||||
|
||||
**After:**
|
||||
```csharp
|
||||
// Exact goal checking (more precise)
|
||||
bool goalMet = comFountainTemp >= recipeHeatingGoal;
|
||||
```
|
||||
|
||||
### 5. Cooling Phase Transition - Updated Logic
|
||||
|
||||
**Before:**
|
||||
```csharp
|
||||
// Using 3°C tolerance around cooling goal
|
||||
bool chocolateAtCoolingTemp = Math.Abs(comFountainTemp - recipeCoolingGoal) <= 3;
|
||||
```
|
||||
|
||||
**After:**
|
||||
```csharp
|
||||
// Check if temperature is at or below cooling goal
|
||||
bool chocolateAtCoolingTemp = comFountainTemp <= recipeCoolingGoal;
|
||||
```
|
||||
|
||||
## Phase-Specific Logic Summary
|
||||
|
||||
### Heating Phase
|
||||
- **Goal**: Reach or exceed heating temperature
|
||||
- **Error Condition**: Temperature below (goal - errorLimit)
|
||||
- **Success Condition**: Temperature >= goal
|
||||
- **Next Phase**: Cooling
|
||||
|
||||
### Cooling Phase
|
||||
- **Goal**: Reach or go below cooling temperature
|
||||
- **Error Condition**: Temperature above (goal + errorLimit)
|
||||
- **Success Condition**: Temperature <= goal
|
||||
- **Next Phase**: Pouring
|
||||
|
||||
### Pouring Phase
|
||||
- **Goal**: Maintain temperature within range
|
||||
- **Error Condition**: Temperature outside (goal ± errorLimit)
|
||||
- **Success Condition**: Temperature within range
|
||||
- **Next Phase**: Recipe completion
|
||||
|
||||
## Error Messages Improved
|
||||
|
||||
### Before
|
||||
- Generic: "Temperature error: 51.0°C (Target: 46°C)"
|
||||
|
||||
### After
|
||||
- **Heating**: "Heating temperature too low: 51.0°C (Target: 46°C)"
|
||||
- **Cooling**: "Cooling temperature too high: 51.0°C (Target: 27°C)"
|
||||
- **Pouring**: "Pouring temperature out of range: 51.0°C (Target: 30°C)"
|
||||
|
||||
## Warning Messages Improved
|
||||
|
||||
### Before
|
||||
- Generic: "Temperature approaching limits"
|
||||
|
||||
### After
|
||||
- **Heating**: "Heating temperature approaching minimum"
|
||||
- **Cooling**: "Cooling temperature approaching maximum"
|
||||
- **Pouring**: "Pouring temperature approaching limits"
|
||||
|
||||
## Expected Behavior After Fix
|
||||
|
||||
### Scenario from Image
|
||||
1. **Current State**: Heating phase with 51.0°C (above 46°C goal)
|
||||
2. **Old Behavior**: ❌ Shows error popup, prevents progression
|
||||
3. **New Behavior**: ✅ Recognizes goal achieved, proceeds to cooling
|
||||
4. **Next Step**: Cooling phase starts automatically
|
||||
|
||||
### Complete Flow
|
||||
1. **Heating Phase**:
|
||||
- Wait for both mixer and chocolate to reach heating goal
|
||||
- No error if temperature exceeds goal
|
||||
- Proceed to cooling when goals met
|
||||
|
||||
2. **Cooling Phase**:
|
||||
- Check if chocolate temperature is at/below cooling goal
|
||||
- If yes: Show cooling delay
|
||||
- If no: Start active cooling
|
||||
- Proceed to pouring when cooling complete
|
||||
|
||||
3. **Pouring Phase**:
|
||||
- Maintain temperature within pouring range
|
||||
- Complete recipe when pouring timer finishes
|
||||
|
||||
## Benefits of the Fix
|
||||
|
||||
### 1. Correct Phase Progression
|
||||
- ✅ Heating phase completes when goals are met
|
||||
- ✅ Cooling phase starts automatically
|
||||
- ✅ No false error popups
|
||||
|
||||
### 2. Improved User Experience
|
||||
- ✅ Clear, phase-specific error messages
|
||||
- ✅ Logical temperature validation
|
||||
- ✅ Smooth phase transitions
|
||||
|
||||
### 3. Enhanced Safety
|
||||
- ✅ Proper error detection for each phase
|
||||
- ✅ Appropriate warnings for each condition
|
||||
- ✅ Maintains safety while allowing progression
|
||||
|
||||
### 4. Better Reliability
|
||||
- ✅ Eliminates false error conditions
|
||||
- ✅ Ensures recipe completion
|
||||
- ✅ Maintains quality control
|
||||
|
||||
## Testing Recommendations
|
||||
|
||||
### Test Scenarios
|
||||
1. **Normal Heating**: Temperature reaches and exceeds goal
|
||||
2. **Slow Heating**: Temperature takes time to reach goal
|
||||
3. **Fast Heating**: Temperature quickly exceeds goal
|
||||
4. **Cooling Transition**: Verify cooling phase starts
|
||||
5. **Error Conditions**: Test actual error scenarios
|
||||
|
||||
### Validation Points
|
||||
- ✅ No error popup when temperature exceeds heating goal
|
||||
- ✅ Cooling phase starts after heating delay completes
|
||||
- ✅ Cooling delay shows when temperature is at/below cooling goal
|
||||
- ✅ Pouring phase starts after cooling completes
|
||||
- ✅ Recipe completes successfully
|
||||
|
||||
## Conclusion
|
||||
|
||||
The fix addresses the core issue where the system incorrectly treated temperatures above the heating goal as errors. With the corrected phase-specific logic, the system now:
|
||||
|
||||
1. **Recognizes heating success** when temperatures reach or exceed the goal
|
||||
2. **Proceeds to cooling phase** automatically after heating delay
|
||||
3. **Shows appropriate errors** only when temperatures are actually problematic
|
||||
4. **Provides clear feedback** for each phase and condition
|
||||
|
||||
This ensures the recipe system works as intended, providing reliable chocolate tempering with proper phase progression and error handling.
|
||||
32
DaireApplication/ViewLocator.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Templates;
|
||||
using DaireApplication.ViewModels;
|
||||
using System;
|
||||
|
||||
namespace DaireApplication
|
||||
{
|
||||
public class ViewLocator : IDataTemplate
|
||||
{
|
||||
|
||||
public Control? Build(object? param)
|
||||
{
|
||||
if (param is null)
|
||||
return null;
|
||||
|
||||
var name = param.GetType().FullName!.Replace("ViewModel", "View", StringComparison.Ordinal);
|
||||
var type = Type.GetType(name);
|
||||
|
||||
if (type != null)
|
||||
{
|
||||
return (Control)Activator.CreateInstance(type)!;
|
||||
}
|
||||
|
||||
return new TextBlock { Text = "Not Found: " + name };
|
||||
}
|
||||
|
||||
public bool Match(object? data)
|
||||
{
|
||||
return data is ViewModelBase;
|
||||
}
|
||||
}
|
||||
}
|
||||
93
DaireApplication/ViewModels/Error.cs
Normal file
@@ -0,0 +1,93 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Threading;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static DaireApplication.Views.MainWindow;
|
||||
|
||||
namespace DaireApplication.ViewModels
|
||||
{
|
||||
public class Error
|
||||
{
|
||||
public enum GridCondition
|
||||
{
|
||||
GridFrequencyHigh,
|
||||
GridFrequencyLow,
|
||||
GridVACHigh,
|
||||
GridVACLow,
|
||||
NoExternalPower,
|
||||
MissingPhase,
|
||||
PhaseSequence,
|
||||
LoadDisconnection,
|
||||
MotorDisconnection,
|
||||
NoBoardCom,
|
||||
NoInternetAccess,
|
||||
ComPort1,
|
||||
ComPort2,
|
||||
HiCurrNeut,
|
||||
HiCurrMot1,
|
||||
HiCurrMot2,
|
||||
}
|
||||
public DateTime errorDate { get; set; }
|
||||
public GridCondition Condition { get; set; }
|
||||
public bool isShowen { get; set; } = false;
|
||||
public bool isDeleted { get; set; } = false;
|
||||
|
||||
public string GetDisplayNames(GridCondition condition)
|
||||
{
|
||||
return condition switch
|
||||
{
|
||||
GridCondition.GridFrequencyHigh => "Grid Frequency High",
|
||||
GridCondition.GridFrequencyLow => "Grid Frequency Low",
|
||||
GridCondition.GridVACHigh => "Grid VAC High",
|
||||
GridCondition.GridVACLow => "Grid VAC Low",
|
||||
GridCondition.NoExternalPower => "No External Power",
|
||||
GridCondition.MissingPhase => "Missing Phase",
|
||||
GridCondition.PhaseSequence => "Phase Sequence",
|
||||
GridCondition.LoadDisconnection => "Load Disconnection",
|
||||
GridCondition.MotorDisconnection => "Motor Disconnection",
|
||||
GridCondition.NoBoardCom => "Communication Timeout",
|
||||
GridCondition.NoInternetAccess => "No InternetAccess",
|
||||
GridCondition.ComPort1 => "Com Port1",
|
||||
GridCondition.ComPort2 => "Com Port2",
|
||||
GridCondition.HiCurrNeut=> "Hi Curr Neut",
|
||||
GridCondition.HiCurrMot1=> "Hi Curr Mot1",
|
||||
GridCondition.HiCurrMot2=> "Hi Curr Mot2",
|
||||
_ => string.Empty
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
public static bool IsInternetAvailable()
|
||||
{
|
||||
try
|
||||
{
|
||||
var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
|
||||
|
||||
foreach (var networkInterface in networkInterfaces)
|
||||
{
|
||||
if (networkInterface.OperationalStatus == OperationalStatus.Up)
|
||||
{
|
||||
using (var ping = new Ping())
|
||||
{
|
||||
var reply = ping.Send("8.8.8.8", 3000); // Pinging Google DNS server with a timeout of 3000ms
|
||||
if (reply != null && reply.Status == IPStatus.Success)
|
||||
{
|
||||
return true; // Internet is available
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false; // Return false if there is any exception (e.g., no network interface found, or errors during checking)
|
||||
}
|
||||
|
||||
return false; // Return false if no network interfaces are available or no successful ping
|
||||
}
|
||||
}
|
||||
}
|
||||
20
DaireApplication/ViewModels/HoldingRegister.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DaireApplication.ViewModels
|
||||
{
|
||||
public class HoldingRegister
|
||||
{
|
||||
public ushort resetError { get; set; } = 0;
|
||||
public ushort hvOut { get; set; } = 0;
|
||||
public ushort lvOut { get; set; } = 0;
|
||||
public ushort motor { get; set; } = 0;
|
||||
public int setTemp1 { get; set; } = -10000;
|
||||
public int setTemp2 { get; set; } = -10000;
|
||||
public int setTemp3 { get; set; } = -10000;
|
||||
public int setTemp4 { get; set; } = -10000;
|
||||
}
|
||||
}
|
||||
7
DaireApplication/ViewModels/MainWindowViewModel.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace DaireApplication.ViewModels
|
||||
{
|
||||
public class MainWindowViewModel : ViewModelBase
|
||||
{
|
||||
public string Greeting { get; } = "Welcome to Avalonia!";
|
||||
}
|
||||
}
|
||||
306
DaireApplication/ViewModels/ModBusMaster.cs
Normal file
@@ -0,0 +1,306 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO.Ports;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AvaloniaApplication1.ViewModels
|
||||
{
|
||||
public class ModBusMaster
|
||||
{
|
||||
public byte slaveId { get; set; } = 0x01; // Slave ID (your ESP slave ID)
|
||||
//byte functionCode = 0x05; // Function code for Write Single Coil
|
||||
//byte coilAddressHigh = 0x00; // Coil address (MSB)
|
||||
//byte coilAddressLow = 0x00; // Coil address (LSB)
|
||||
//byte coilValueHigh = 0x00; // Coil value (0xFF00 to turn on, 0x0000 to turn off)
|
||||
//byte coilValueLow = 0x00;
|
||||
|
||||
// Function to read coils
|
||||
public async Task<bool[]> ReadCoils(SerialPort port, ushort startAddress, ushort numberOfCoils)
|
||||
{
|
||||
try
|
||||
{
|
||||
byte functionCode = 0x01; // Function code for Read Coils
|
||||
byte[] frame = new byte[6]; // Request frame size (without CRC)
|
||||
|
||||
// Construct the request frame
|
||||
frame[0] = slaveId; // Slave address
|
||||
frame[1] = functionCode; // Function code (0x01 for Read Coils)
|
||||
frame[2] = (byte)(startAddress >> 8); // Start address high byte
|
||||
frame[3] = (byte)(startAddress & 0xFF); // Start address low byte
|
||||
frame[4] = (byte)(numberOfCoils >> 8); // Number of coils high byte
|
||||
frame[5] = (byte)(numberOfCoils & 0xFF); // Number of coils low byte
|
||||
|
||||
// Calculate CRC and append it to the frame
|
||||
byte[] crc = CalculateCRC(frame);
|
||||
byte[] fullFrame = new byte[frame.Length + crc.Length];
|
||||
Array.Copy(frame, fullFrame, frame.Length);
|
||||
Array.Copy(crc, 0, fullFrame, frame.Length, crc.Length);
|
||||
|
||||
// Send the frame over the serial port
|
||||
port.DiscardOutBuffer();
|
||||
port.DiscardInBuffer();
|
||||
|
||||
port.Write(fullFrame, 0, fullFrame.Length);
|
||||
Thread.Sleep(500);
|
||||
Console.WriteLine("Read Coils request sent.");
|
||||
|
||||
// Buffer for the response (modbus slave response size can vary)
|
||||
byte[] response = new byte[256];
|
||||
int bytesRead = port.Read(response, 0, response.Length);
|
||||
Console.WriteLine("Response Coils sent.");
|
||||
|
||||
|
||||
// Ensure that the response is valid (check slave address and function code)
|
||||
if (response[0] != slaveId || response[1] != functionCode)
|
||||
{
|
||||
Console.WriteLine("Invalid response or error in slave response.");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Calculate the number of bytes based on the number of coils
|
||||
int expectedByteCount = (numberOfCoils + 7) / 8;
|
||||
if (response[2] != expectedByteCount)
|
||||
{
|
||||
Console.WriteLine("Incorrect byte count in the response.");
|
||||
return null;
|
||||
}
|
||||
|
||||
// The response bytes are in bit form, and we need to extract them
|
||||
bool[] coilStates = new bool[numberOfCoils]; // Array to store the coil states
|
||||
int byteIndex = 3; // Start reading from byte 3 (after slave ID and function code)
|
||||
byte coilByte = response[byteIndex]; // The byte representing the coil states
|
||||
|
||||
// Loop over all coils and check the corresponding bit
|
||||
for (int coilIndex = 0; coilIndex < numberOfCoils; coilIndex++)
|
||||
{
|
||||
// Check the state of the coil by checking the corresponding bit in coilByte
|
||||
coilStates[coilIndex] = coilByte == 1 ? true : false; /*(coilByte & (1 << (7 - coilIndex))) != 0;*/
|
||||
}
|
||||
if (coilStates==null)
|
||||
{
|
||||
Console.WriteLine("status wael: null");
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"status: {coilStates[0]}");
|
||||
|
||||
}
|
||||
|
||||
return coilStates;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"error wael: {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Function to write a single coil
|
||||
public async Task<byte[]> WriteSingleCoil(ushort coilAddress, bool state)
|
||||
{
|
||||
byte functionCode = 0x05;
|
||||
byte[] frame = new byte[6];
|
||||
|
||||
frame[0] = slaveId; // Slave address
|
||||
frame[1] = functionCode; // Function code
|
||||
frame[2] = (byte)(coilAddress >> 8); // Coil address high byte
|
||||
frame[3] = (byte)(coilAddress & 0xFF); // Coil address low byte
|
||||
frame[4] = (byte)(state ? 0xFF : 0x00); // Coil value (ON=0xFF, OFF=0x00)
|
||||
frame[5] = (byte)(0x00); // Coil value (ON=0xFF, OFF=0x00)
|
||||
|
||||
// Calculate CRC and append it
|
||||
byte[] crc = CalculateCRC(frame);
|
||||
byte[] fullFrame = new byte[frame.Length + crc.Length];
|
||||
Array.Copy(frame, fullFrame, frame.Length);
|
||||
Array.Copy(crc, 0, fullFrame, frame.Length, crc.Length);
|
||||
|
||||
return fullFrame;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Function to write multiple coils
|
||||
public byte[] WriteMultipleCoils( ushort startAddress, bool[] coilValues)
|
||||
{
|
||||
byte functionCode = 0x0F;
|
||||
int byteCount = (coilValues.Length + 7) / 8; // Calculate the number of bytes needed
|
||||
byte[] frame = new byte[5 + byteCount]; // Basic frame without CRC
|
||||
|
||||
frame[0] = slaveId; // Slave address
|
||||
frame[1] = functionCode; // Function code
|
||||
frame[2] = (byte)(startAddress >> 8); // Start address high byte
|
||||
frame[3] = (byte)(startAddress & 0xFF); // Start address low byte
|
||||
frame[4] = (byte)(coilValues.Length); // Number of coils
|
||||
|
||||
frame[5] = (byte)byteCount; // Number of bytes to follow (coil values)
|
||||
for (int i = 0; i < coilValues.Length; i++)
|
||||
{
|
||||
int byteIndex = 5 + 1 + (i / 8); // Start at byte 6, accounting for byte count
|
||||
if (coilValues[i])
|
||||
{
|
||||
frame[byteIndex] |= (byte)(1 << (i % 8)); // Set the bit corresponding to the coil
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate CRC and append it
|
||||
byte[] crc = CalculateCRC(frame);
|
||||
byte[] fullFrame = new byte[frame.Length + crc.Length];
|
||||
Array.Copy(frame, fullFrame, frame.Length);
|
||||
Array.Copy(crc, 0, fullFrame, frame.Length, crc.Length);
|
||||
|
||||
return fullFrame;
|
||||
}
|
||||
// Function to write multiple registers
|
||||
public async Task<byte[]> WriteSingleRegister(ushort startAddress, int value)
|
||||
{
|
||||
byte functionCode = 0x06; // Function code for writing a single register
|
||||
byte[] frame = new byte[6]; // Basic frame without CRC
|
||||
|
||||
frame[0] = slaveId; // Slave address
|
||||
frame[1] = functionCode; // Function code
|
||||
frame[2] = (byte)(startAddress >> 8); // Start address high byte
|
||||
frame[3] = (byte)(startAddress & 0xFF); // Start address low byte
|
||||
frame[4] = (byte)(value >> 8); // Register value high byte
|
||||
frame[5] = (byte)(value & 0xFF); // Register value low byte
|
||||
|
||||
// Calculate CRC and append it
|
||||
byte[] crc = CalculateCRC(frame);
|
||||
byte[] fullFrame = new byte[frame.Length + crc.Length];
|
||||
Array.Copy(frame, fullFrame, frame.Length);
|
||||
Array.Copy(crc, 0, fullFrame, frame.Length, crc.Length);
|
||||
|
||||
return fullFrame;
|
||||
}
|
||||
public async Task<byte[]> WriteSingleRegister(ushort startAddress, ushort value)
|
||||
{
|
||||
byte functionCode = 0x06; // Function code for writing a single register
|
||||
byte[] frame = new byte[6]; // Basic frame without CRC
|
||||
|
||||
frame[0] = slaveId; // Slave address
|
||||
frame[1] = functionCode; // Function code
|
||||
frame[2] = (byte)(startAddress >> 8); // Start address high byte
|
||||
frame[3] = (byte)(startAddress & 0xFF); // Start address low byte
|
||||
frame[4] = (byte)(value >> 8); // Register value high byte
|
||||
frame[5] = (byte)(value & 0xFF); // Register value low byte
|
||||
|
||||
// Calculate CRC and append it
|
||||
byte[] crc = CalculateCRC(frame);
|
||||
byte[] fullFrame = new byte[frame.Length + crc.Length];
|
||||
Array.Copy(frame, fullFrame, frame.Length);
|
||||
Array.Copy(crc, 0, fullFrame, frame.Length, crc.Length);
|
||||
|
||||
return fullFrame;
|
||||
}
|
||||
public async Task<byte[]> ReadHoldingRegister(ushort startAddress, ushort numberOfRegisters)
|
||||
{
|
||||
byte functionCode = 0x03; // Function code for reading holding registers
|
||||
byte[] frame = new byte[6]; // Basic frame without CRC
|
||||
|
||||
frame[0] = slaveId; // Slave address
|
||||
frame[1] = functionCode; // Function code
|
||||
frame[2] = (byte)(startAddress >> 8); // Start address high byte
|
||||
frame[3] = (byte)(startAddress & 0xFF); // Start address low byte
|
||||
frame[4] = (byte)(numberOfRegisters >> 8); // Number of registers high byte
|
||||
frame[5] = (byte)(numberOfRegisters & 0xFF); // Number of registers low byte
|
||||
|
||||
// Calculate CRC and append it
|
||||
byte[] crc = CalculateCRC(frame);
|
||||
byte[] fullFrame = new byte[frame.Length + crc.Length];
|
||||
Array.Copy(frame, fullFrame, frame.Length);
|
||||
Array.Copy(crc, 0, fullFrame, frame.Length, crc.Length);
|
||||
|
||||
return fullFrame;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public async Task<byte[]> ReadInputRegisters(ushort startAddress, ushort numberOfRegisters)
|
||||
{
|
||||
byte functionCode = 0x04; // Function code for reading input registers
|
||||
byte[] frame = new byte[6]; // Basic frame without CRC
|
||||
|
||||
frame[0] = slaveId; // Slave address
|
||||
frame[1] = functionCode; // Function code
|
||||
frame[2] = (byte)(startAddress >> 8); // Start address high byte
|
||||
frame[3] = (byte)(startAddress & 0xFF); // Start address low byte
|
||||
frame[4] = (byte)(numberOfRegisters >> 8); // Number of registers high byte
|
||||
frame[5] = (byte)(numberOfRegisters & 0xFF); // Number of registers low byte
|
||||
|
||||
// Calculate CRC and append it
|
||||
byte[] crc = CalculateCRC(frame);
|
||||
byte[] fullFrame = new byte[frame.Length + crc.Length];
|
||||
Array.Copy(frame, fullFrame, frame.Length);
|
||||
Array.Copy(crc, 0, fullFrame, frame.Length, crc.Length);
|
||||
|
||||
return fullFrame;
|
||||
}
|
||||
|
||||
|
||||
public async Task<byte[]> WriteMultipleRegisters(ushort startAddress, float[] values)
|
||||
{
|
||||
byte functionCode = 0x10; // Function code for writing multiple registers
|
||||
byte byteCount = (byte)(values.Length * 2); // Total number of bytes for values
|
||||
byte[] frame = new byte[7 + byteCount]; // Frame without CRC
|
||||
|
||||
frame[0] = slaveId; // Slave address
|
||||
frame[1] = functionCode; // Function code
|
||||
frame[2] = (byte)(startAddress >> 8); // Start address high byte
|
||||
frame[3] = (byte)(startAddress & 0xFF); // Start address low byte
|
||||
frame[4] = (byte)(values.Length >> 8); // Number of registers high byte
|
||||
frame[5] = (byte)(values.Length & 0xFF); // Number of registers low byte
|
||||
frame[6] = byteCount; // Byte count
|
||||
|
||||
for (int i = 0; i < values.Length; i++)
|
||||
{
|
||||
short val = unchecked((short)values[i]);
|
||||
frame[7 + i * 2] = (byte)(val >> 8); // Register value high byte
|
||||
frame[8 + i * 2] = (byte)(val & 0xFF); // Register value low byte1
|
||||
}
|
||||
|
||||
// Calculate CRC and append it
|
||||
byte[] crc = CalculateCRC(frame);
|
||||
byte[] fullFrame = new byte[frame.Length + crc.Length];
|
||||
Array.Copy(frame, fullFrame, frame.Length);
|
||||
Array.Copy(crc, 0, fullFrame, frame.Length, crc.Length);
|
||||
|
||||
return fullFrame;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Function to calculate CRC16 for Modbus RTU frame
|
||||
public byte[] CalculateCRC(byte[] data)
|
||||
{
|
||||
ushort crc = 0xFFFF;
|
||||
|
||||
foreach (byte byteData in data)
|
||||
{
|
||||
crc ^= byteData;
|
||||
|
||||
for (int i = 8; i > 0; i--)
|
||||
{
|
||||
if ((crc & 0x0001) == 0x0001)
|
||||
{
|
||||
crc >>= 1;
|
||||
crc ^= 0xA001;
|
||||
}
|
||||
else
|
||||
{
|
||||
crc >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new byte[] { (byte)(crc & 0xFF), (byte)((crc >> 8) & 0xFF) };
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
8
DaireApplication/ViewModels/ViewModelBase.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using ReactiveUI;
|
||||
|
||||
namespace DaireApplication.ViewModels
|
||||
{
|
||||
public class ViewModelBase : ReactiveObject
|
||||
{
|
||||
}
|
||||
}
|
||||
69
DaireApplication/ViewModels/X11CursorHider.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
public class X11CursorHider
|
||||
{
|
||||
const string X11Lib = "libX11.so";
|
||||
|
||||
[DllImport(X11Lib)]
|
||||
static extern IntPtr XOpenDisplay(IntPtr display);
|
||||
|
||||
[DllImport(X11Lib)]
|
||||
static extern int XCloseDisplay(IntPtr display);
|
||||
|
||||
[DllImport(X11Lib)]
|
||||
static extern IntPtr XCreatePixmap(IntPtr display, IntPtr drawable, uint width, uint height, uint depth);
|
||||
|
||||
[DllImport(X11Lib)]
|
||||
static extern IntPtr XCreateBitmapFromData(IntPtr display, IntPtr drawable, byte[] data, uint width, uint height);
|
||||
|
||||
[DllImport(X11Lib)]
|
||||
static extern IntPtr XCreatePixmapCursor(IntPtr display, IntPtr source, IntPtr mask, ref XColor foreground, ref XColor background, uint x, uint y);
|
||||
|
||||
[DllImport(X11Lib)]
|
||||
static extern int XDefineCursor(IntPtr display, IntPtr window, IntPtr cursor);
|
||||
|
||||
[DllImport(X11Lib)]
|
||||
static extern int XFreeCursor(IntPtr display, IntPtr cursor);
|
||||
|
||||
[DllImport(X11Lib)]
|
||||
static extern int XFlush(IntPtr display);
|
||||
|
||||
[DllImport(X11Lib)]
|
||||
static extern IntPtr XDefaultRootWindow(IntPtr display);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct XColor
|
||||
{
|
||||
public ulong pixel;
|
||||
public ushort red, green, blue;
|
||||
public byte flags;
|
||||
public byte pad;
|
||||
}
|
||||
|
||||
public static void HideCursor()
|
||||
{
|
||||
IntPtr display = XOpenDisplay(IntPtr.Zero);
|
||||
if (display == IntPtr.Zero)
|
||||
{
|
||||
Console.WriteLine("Cannot open X display");
|
||||
return;
|
||||
}
|
||||
|
||||
IntPtr root = XDefaultRootWindow(display);
|
||||
|
||||
byte[] emptyData = new byte[1] { 0 }; // 1x1 empty bitmap
|
||||
IntPtr pixmap = XCreateBitmapFromData(display, root, emptyData, 1, 1);
|
||||
|
||||
XColor dummy = new XColor();
|
||||
|
||||
IntPtr invisibleCursor = XCreatePixmapCursor(display, pixmap, pixmap, ref dummy, ref dummy, 0, 0);
|
||||
|
||||
XDefineCursor(display, root, invisibleCursor);
|
||||
XFlush(display);
|
||||
|
||||
// Keep the cursor hidden until app closes, remember to call:
|
||||
// XFreeCursor(display, invisibleCursor);
|
||||
// XCloseDisplay(display);
|
||||
}
|
||||
}
|
||||
487
DaireApplication/Views/MainWindow.axaml
Normal file
@@ -0,0 +1,487 @@
|
||||
<Window xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:vm="using:DaireApplication.ViewModels"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
x:Class="DaireApplication.Views.MainWindow"
|
||||
Icon="/Assets/avalonia-logo.ico"
|
||||
Title="DaireApplication"
|
||||
Background="#B3B3B3"
|
||||
FontFamily="Helvetica"
|
||||
WindowState="Maximized"
|
||||
SystemDecorations="None"
|
||||
Topmost="False"
|
||||
|
||||
Width="1280" Height="800">
|
||||
|
||||
<Grid RowDefinitions="Auto,2*,Auto">
|
||||
<!-- Titel Bar-->
|
||||
<Grid x:Name="TitelBar" Grid.Row="0" Background="WhiteSmoke" Height="90" Margin="0">
|
||||
<Grid.Styles>
|
||||
<Style Selector="Button">
|
||||
<Setter Property="Background" Value="Transparent"></Setter>
|
||||
</Style>
|
||||
<Style Selector="Button:pointerover /template/ContentPresenter">
|
||||
<Setter Property="Foreground" Value="Black"></Setter>
|
||||
<Setter Property="Background" Value="Transparent"></Setter>
|
||||
|
||||
</Style>
|
||||
|
||||
</Grid.Styles>
|
||||
|
||||
<Grid ColumnDefinitions="Auto,5*,Auto">
|
||||
<StackPanel Width="160" Height="40" Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Left" Grid.Column="0" Margin="0,0,40,0">
|
||||
<Button x:Name="logoBtn" BorderThickness="0" Background="Transparent" Width="220" Height="200">
|
||||
<Button.Template>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" BorderBrush="Transparent" BorderThickness="1" Background="Transparent">
|
||||
<ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Button.Template>
|
||||
<Image Source="/Assets/Logo.png" Width="160" Height="40" />
|
||||
</Button>
|
||||
|
||||
|
||||
|
||||
</StackPanel>
|
||||
<StackPanel Background="Transparent" HorizontalAlignment="Left" Grid.Column="1" Orientation="Horizontal" Spacing="-10" ZIndex="-1">
|
||||
|
||||
<!-- Home Button with One-Sided Arrow -->
|
||||
<Button x:Name="HomeTrack" BorderThickness="2" Width="140" Height="60" Click="HomeTraclBtn" >
|
||||
<Grid Width="140" Height="50" >
|
||||
<Polygon x:Name="HomePolygon" Points="20,0 120,0 140,25 120,50 20,50 20,0"
|
||||
Stroke="Black" StrokeThickness="2" Fill="#E6E6E6"/>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center" >
|
||||
<Image Source="/Assets/Home.png" Width="20" Height="20" Margin="5,0,5,0" />
|
||||
<TextBlock Text="HOME" FontSize="18" FontWeight="Normal" Foreground="Black"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Button>
|
||||
|
||||
<!-- Recipe Selection Button -->
|
||||
<Button x:Name="RecipeSelTrack" BorderThickness="2" Width="150" Height="60" Click="RecipeSelTrackBtn">
|
||||
<Grid Width="150" Height="50">
|
||||
<Polygon x:Name="RecipeSelPolygon" Points="0,0 130,0 150,25 130,50 0,50 20,25"
|
||||
Stroke="Black" StrokeThickness="2" Fill="#E6E6E6"/>
|
||||
<TextBlock Text="RECIPE SEL." FontSize="18" Margin="10,0,0,0"
|
||||
Foreground="Black" HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"/>
|
||||
</Grid>
|
||||
</Button>
|
||||
<!-- Recipe Panel Button -->
|
||||
<Button x:Name="RecipePanelTrack" BorderThickness="2" Width="170" Height="60" Click="RecipeSelTrackBtn">
|
||||
<Grid Width="170" Height="50">
|
||||
<Polygon x:Name="RecipePanelPolygon" Points="0,0 150,0 170,25 150,50 0,50 20,25"
|
||||
Stroke="Black" StrokeThickness="2" Fill="#E6E6E6"/>
|
||||
<TextBlock Text="RECIPE PANEL" FontSize="18" FontWeight="Normal"
|
||||
Foreground="Black" HorizontalAlignment="Center"
|
||||
Padding="10,0,0,0"
|
||||
VerticalAlignment="Center"/>
|
||||
</Grid>
|
||||
</Button>
|
||||
|
||||
<!-- Settings Button -->
|
||||
<Button x:Name="SettingTrack" BorderThickness="2" Width="150" Height="60" Click="SettingTrackBtn">
|
||||
<Grid Width="150" Height="50">
|
||||
<Polygon x:Name="SettingPolygon" Points="0,0 130,0 150,25 130,50 0,50 20,25"
|
||||
Stroke="Black" StrokeThickness="2" Fill="#E6E6E6"/>
|
||||
<TextBlock Text="SETTINGS" FontSize="18" FontWeight="Normal"
|
||||
Foreground="Black" HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"/>
|
||||
</Grid>
|
||||
</Button>
|
||||
|
||||
<!-- Recipe Edit Button -->
|
||||
<Button x:Name="RecipeEditTrack" BorderThickness="2" Width="170" Height="60">
|
||||
<Grid Width="170" Height="50">
|
||||
<Polygon x:Name="RecipeEditPolygon" Points="0,0 150,0 170,25 150,50 0,50 20,25"
|
||||
Stroke="#A4275D" StrokeThickness="2" Fill="#E6E6E6"/>
|
||||
<TextBlock Text="RECIPE EDIT" FontSize="18" FontWeight="Normal"
|
||||
Foreground="Black" HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"/>
|
||||
</Grid>
|
||||
</Button>
|
||||
<!-- Run Interface Button -->
|
||||
<Button x:Name="RunInterfaceTrack" BorderThickness="2" Width="200" Height="60" IsVisible="False">
|
||||
<Grid Width="200" Height="50">
|
||||
<Polygon x:Name="RunInterfacePolygon" Points="0,0 170,0 190,25 170,50 0,50 20,25"
|
||||
Stroke="#A4275D" StrokeThickness="2" Fill="#E6E6E6"/>
|
||||
<TextBlock Text="RUN INTERFACE" FontSize="18" FontWeight="Normal" Margin="0,0,0,0"
|
||||
Foreground="Black" HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"/>
|
||||
|
||||
</Grid>
|
||||
</Button>
|
||||
<!-- DIAGNOSTICS Button -->
|
||||
<Button x:Name="DiagnosticsTrack" BorderThickness="2" Width="170" Height="60" IsVisible="False" Click="DiagnosticsBtn">
|
||||
<Grid Width="170" Height="50">
|
||||
<Polygon x:Name="DiagnosticsPolygon" Points="0,0 150,0 170,25 150,50 0,50 20,25"
|
||||
Stroke="#A4275D" StrokeThickness="2" Fill="#E6E6E6"/>
|
||||
<TextBlock Text="DIAGNOSTICS" FontSize="20" FontWeight="Normal" Margin="11,0,0,0"
|
||||
Foreground="Black" HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"/>
|
||||
|
||||
</Grid>
|
||||
</Button>
|
||||
|
||||
<!-- SOFTWARE Button -->
|
||||
<Button x:Name="SoftwareTrack" BorderThickness="2" Width="170" Height="60" Margin="0,0,0,0" IsVisible="False" Click="SoftwareBtn">
|
||||
<Grid Width="170" Height="50">
|
||||
<Polygon x:Name="SoftwarePolygon" Points="0,0 150,0 170,25 150,50 0,50 20,25"
|
||||
Stroke="#A4275D" StrokeThickness="2" Fill="#E6E6E6"/>
|
||||
<TextBlock Text="SOFTWARE" FontSize="18" FontWeight="Normal" Margin="0,0,0,0"
|
||||
Foreground="Black" HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"/>
|
||||
|
||||
</Grid>
|
||||
</Button>
|
||||
<!-- ADVANCE SETTINGS Button -->
|
||||
<Button x:Name="AdvanceSettingsTrack" BorderThickness="2" Width="220" Height="60" Margin="0,0,0,0" IsVisible="False" Click="AdvanceSettingsView">
|
||||
<Grid Width="220" Height="50">
|
||||
<Polygon x:Name="AdvanceSettingsPolygon" Points="0,0 200,0 220,25 200,50 0,50 20,25"
|
||||
Stroke="#A4275D" StrokeThickness="2" Fill="#E6E6E6"/>
|
||||
<TextBlock Text="ADVANCE SETTINGS" FontSize="18" FontWeight="Normal" Margin="0,0,0,0"
|
||||
Foreground="Black" HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"/>
|
||||
|
||||
</Grid>
|
||||
</Button>
|
||||
|
||||
<!-- MANUAL CONTROL Button -->
|
||||
<Button x:Name="ManualControlTrack" BorderThickness="2" Width="200" Height="60" IsVisible="False" Click="ChefManualBtn">
|
||||
<Grid Width="200" Height="50">
|
||||
<Polygon x:Name="ManualControlPolygon" Points="0,0 170,0 190,25 170,50 0,50 20,25"
|
||||
Stroke="#A4275D" StrokeThickness="2" Fill="#E6E6E6"/>
|
||||
<TextBlock Text="MANUAL CONTROL" FontSize="18" FontWeight="Normal" Margin="0,0,-5,0"
|
||||
Foreground="Black" HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"/>
|
||||
|
||||
</Grid>
|
||||
</Button>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
|
||||
|
||||
<StackPanel Grid.Column="2"
|
||||
|
||||
HorizontalAlignment="Right" Orientation="Horizontal" Margin="0,0,5,0"
|
||||
Spacing="0">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock x:Name="version" VerticalAlignment="Center" FontSize="30" Foreground="Black" Margin="0,0,0,0" IsVisible="True" >V0.6</TextBlock>
|
||||
|
||||
<Button x:Name="errorLogoBtn" Background="Transparent" Click="errorLogoClick">
|
||||
<Image x:Name="errorLogo" IsVisible="False" Tag="Error" Source="/Assets/errorIcon.png" Width="60" Height="60" Stretch="Uniform" Margin="0,0,0,0" ></Image>
|
||||
</Button>
|
||||
<Button Background="Transparent" Click="warningLogoClick">
|
||||
<Image x:Name="warningLogo" IsVisible="False" Tag="Warning" Source="/Assets/warningIcon.png" Height="60" Margin="0,0,0,0" ></Image>
|
||||
</Button>
|
||||
<Image x:Name="wifiLogo" IsVisible="False" Tag="Warning" Source="/Assets/wifi.png" Height="60" Margin="0,0,0,0"></Image>
|
||||
<Image x:Name="nowifiLogo" IsVisible="True" Tag="Warning" Source="/Assets/wifioff.png" Height="60" Margin="0,0,0,0"></Image>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Margin="0,0,0,0">
|
||||
<!-- Recipe Button -->
|
||||
<Button x:Name="TitleBtn" Background="#A4275D" Foreground="White"
|
||||
Width="180" Height="50" CornerRadius="10" Margin="10,0,30,0" VerticalContentAlignment="Center" HorizontalContentAlignment="Center"
|
||||
>
|
||||
<Button.Styles>
|
||||
<Style Selector="Button:pointerover /template/ContentPresenter">
|
||||
<Setter Property="Background" Value="#A4275D"/>
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
</Style>
|
||||
<Style Selector="TextBlock">
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
|
||||
</Style>
|
||||
</Button.Styles>
|
||||
<TextBlock Text="Product" Foreground="White" FontSize="24" FontWeight="Normal"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center" x:Name="Title"></TextBlock>
|
||||
|
||||
</Button>
|
||||
<!-- minimize Button -->
|
||||
<Button x:Name="minimizeBtn" CornerRadius="10" Width="50" Height="50" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Foreground="White" Background="#666666" FontSize="24" FontWeight="Normal"
|
||||
Content="-"
|
||||
IsVisible="False">
|
||||
<Button.Styles>
|
||||
<Style Selector="Button:pointerover /template/ContentPresenter">
|
||||
<Setter Property="Background" Value="LightGray"/>
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
</Style>
|
||||
</Button.Styles>
|
||||
|
||||
</Button>
|
||||
<!-- User Button -->
|
||||
<Button Content="ALL USERS" x:Name="UserName" CornerRadius="10" Width="220" Height="50" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Foreground="White" Background="#666666" FontSize="24" FontWeight="Normal"
|
||||
>
|
||||
<Button.Styles>
|
||||
<Style Selector="Button:pointerover /template/ContentPresenter">
|
||||
<Setter Property="Background" Value="LightGray"/>
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
</Style>
|
||||
</Button.Styles>
|
||||
|
||||
</Button>
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
<!-- Main Area-->
|
||||
|
||||
|
||||
<ContentControl Padding="0" Margin="0" Grid.Row="1" x:Name="ContentArea" Height="620" Background="#b3b3b3" />
|
||||
|
||||
<!--Footer-->
|
||||
<Grid Grid.Row="2" Margin="0,0,0,0" ColumnDefinitions="Auto,*,Auto" Background="White" x:Name="footer" Height="90" >
|
||||
<Grid.Styles>
|
||||
<Style Selector="Button.RecipeStart:pointerover /template/ContentPresenter">
|
||||
<Setter Property="Foreground" Value="White"></Setter>
|
||||
<Setter Property="Background" Value="#008000"></Setter>
|
||||
</Style>
|
||||
<Style Selector="Button.PreHeating:pointerover /template/ContentPresenter">
|
||||
<Setter Property="Foreground" Value="White"></Setter>
|
||||
<Setter Property="Background" Value="#d45500"></Setter>
|
||||
</Style>
|
||||
</Grid.Styles>
|
||||
<StackPanel Grid.Column="0" Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Center" Spacing="20" Height="80" Margin="20,0,0,0">
|
||||
|
||||
|
||||
<StackPanel x:Name="footerStartBtn" Orientation="Horizontal" Spacing="20" IsVisible="False">
|
||||
<!-- START Button -->
|
||||
|
||||
<Button Content="START RECIPE"
|
||||
x:Name="recipeStartBtn" Classes="RecipeStart" Width="320" Height="60" FontSize="40"
|
||||
Background="#008000" Foreground="White" BorderBrush="#008000"
|
||||
CornerRadius="10" HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
|
||||
VerticalAlignment="Center" Padding="0,0,0,0" Margin="0,0,0,0" Click="RecipeStartBtn" >
|
||||
<Button.Styles>
|
||||
<!-- Custom Style for Disabled Button -->
|
||||
<Style Selector="Button:disabled /template/ContentPresenter">
|
||||
<Setter Property="Background" Value="#E6E6E6"/>
|
||||
<Setter Property="Foreground" Value="#231F20"/>
|
||||
|
||||
</Style>
|
||||
</Button.Styles>
|
||||
</Button>
|
||||
|
||||
|
||||
<!--PRE-HEATING Button-->
|
||||
|
||||
<Button Content="PRE-HEATING" x:Name="PreHeatingBtn" Classes="PreHeating" Width="320" Height="60" FontSize="40"
|
||||
Background="#d45500" Foreground="White" BorderBrush="#d45500"
|
||||
CornerRadius="10" HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
|
||||
VerticalAlignment="Center" Padding="0,0,0,0" Margin="0,0,0,0"
|
||||
Click="PreHeatingClick" >
|
||||
<Button.Styles>
|
||||
<!-- Custom Style for Disabled Button -->
|
||||
<Style Selector="Button:disabled /template/ContentPresenter">
|
||||
<Setter Property="Background" Value="#E6E6E6"/>
|
||||
<Setter Property="Foreground" Value="#231F20"/>
|
||||
|
||||
</Style>
|
||||
</Button.Styles>
|
||||
</Button>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</StackPanel>
|
||||
<StackPanel x:Name="adminBtns" IsVisible="False" Grid.Column="0" Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Center" Spacing="20" Height="80">
|
||||
<!-- DIAGNOSTICS Button -->
|
||||
<StackPanel.Styles>
|
||||
<Style Selector="Button:pointerover /template/ContentPresenter">
|
||||
<Setter Property="Foreground" Value="Black"></Setter>
|
||||
<Setter Property="Background" Value="LightGray"></Setter>
|
||||
<Setter Property="RenderTransform" Value="scale(1.11)"></Setter>
|
||||
</Style>
|
||||
|
||||
|
||||
|
||||
</StackPanel.Styles>
|
||||
|
||||
<Button Content="DIAGNOSTICS" Width="300" Height="60" FontSize="28" FontWeight="Normal"
|
||||
Background="LightGray" Foreground="Black" BorderBrush="LightGray"
|
||||
CornerRadius="10" HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
|
||||
VerticalAlignment="Center" Margin="40,0,0,0" IsVisible="True" Click="DiagnosticsBtn"/>
|
||||
|
||||
<Button Content="SOFTWARE" Width="240" Height="60" FontSize="28" FontWeight="Normal"
|
||||
Background="LightGray" Foreground="Black" BorderBrush="LightGray"
|
||||
CornerRadius="10" HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
|
||||
VerticalAlignment="Center" Margin="40,0,0,0" IsVisible="True" Click="SoftwareBtn"/>
|
||||
|
||||
<!-- EDIT Button -->
|
||||
<!--
|
||||
<Button Content="EDIT" Click="EditClick" Width="120" Height="50" FontSize="20"
|
||||
Background="Transparent" Foreground="Gray" BorderBrush="#B0B0B0"
|
||||
CornerRadius="10" BorderThickness="2" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" />
|
||||
-->
|
||||
|
||||
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel x:Name="chefBtns" IsVisible="False" Grid.Column="0" Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Center" Spacing="20" Height="80">
|
||||
<!-- DIAGNOSTICS Button -->
|
||||
<StackPanel.Styles>
|
||||
<Style Selector="Button:pointerover /template/ContentPresenter">
|
||||
<Setter Property="Foreground" Value="Black"></Setter>
|
||||
<Setter Property="Background" Value="LightGray"></Setter>
|
||||
<Setter Property="RenderTransform" Value="scale(1.11)"></Setter>
|
||||
</Style>
|
||||
|
||||
|
||||
|
||||
</StackPanel.Styles>
|
||||
|
||||
<Button Content="MANUAL CONTROL" Width="300" Height="60" FontSize="28" FontWeight="Normal"
|
||||
Background="LightGray" Foreground="Black" BorderBrush="LightGray"
|
||||
CornerRadius="10" HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
|
||||
VerticalAlignment="Center" Margin="40,0,0,0" IsVisible="True" Click="ChefManualBtn"/>
|
||||
|
||||
|
||||
|
||||
|
||||
</StackPanel>
|
||||
|
||||
<Grid Grid.Column="1" x:Name="TextCenter" Margin="" >
|
||||
<StackPanel VerticalAlignment="Center">
|
||||
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
FontSize="35" Foreground="Green" x:Name="footerMsg"
|
||||
IsVisible="True" Padding="0,0,0,0"
|
||||
TextWrapping="WrapWithOverflow">Ready</TextBlock>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
|
||||
</Grid>
|
||||
<Grid Grid.Column="2" RowDefinitions="*,*" x:Name="footerDateContainer" IsVisible="" Height="55" VerticalAlignment="Center" Margin="0,0,10,0" >
|
||||
<StackPanel Grid.Row="0" >
|
||||
<TextBlock VerticalAlignment="Bottom"
|
||||
FontSize="28" Foreground="Black" HorizontalAlignment="Right"
|
||||
Margin="0,0,5,0" x:Name="footerTime">12:55 PM</TextBlock>
|
||||
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Row="1" >
|
||||
<TextBlock HorizontalAlignment="Right" VerticalAlignment="Bottom"
|
||||
FontSize="28" Foreground="Black" Padding="0,0,0,0" Margin="0,0,0,0" x:Name="footerDate">20/02/2025</TextBlock>
|
||||
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</Grid>
|
||||
|
||||
|
||||
<!-- Overlay Background for Popup -->
|
||||
<Border x:Name="errorPopupOverlay" Background="#80000000" Grid.RowSpan="3" IsVisible="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ZIndex="99"
|
||||
PointerPressed="OnErrorPopupOverlayPointerPressed">
|
||||
<!-- Popup User Control -->
|
||||
|
||||
<!-- Module for Name Entry -->
|
||||
<Grid PointerPressed="" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="20" IsVisible="True">
|
||||
<Border Background="White" CornerRadius="10" Padding="20" BorderThickness="1" ZIndex="101" BorderBrush="#CCC">
|
||||
<StackPanel Spacing="15">
|
||||
<!-- Label for Text Input -->
|
||||
<!-- Label -->
|
||||
<Grid ColumnDefinitions="Auto,*">
|
||||
<Grid Grid.Column="0">
|
||||
<TextBlock x:Name="errorTitel" Text="Error"
|
||||
FontSize="20"
|
||||
FontWeight="Bold"
|
||||
Foreground="Red"
|
||||
Margin="0,0,40,8" />
|
||||
</Grid>
|
||||
<Grid Grid.Column="1">
|
||||
<Button Background="Red" Foreground="White"
|
||||
CornerRadius="5"
|
||||
Width="100"
|
||||
Height="40"
|
||||
VerticalContentAlignment="Center"
|
||||
HorizontalContentAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center"
|
||||
x:Name="resetErrorsBtn"
|
||||
Click="ResetErrors">Reset Errors</Button>
|
||||
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
|
||||
<StackPanel>
|
||||
<TextBlock x:Name="errorMsg" Text=""
|
||||
FontSize="20"
|
||||
FontWeight="Bold"
|
||||
Foreground="Black"
|
||||
Margin="0,0,0,8" />
|
||||
|
||||
</StackPanel>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Button Panel -->
|
||||
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
<!-- Overlay Background for Popup -->
|
||||
<Border x:Name="warningPopupOverlay" Background="#80000000" Grid.RowSpan="3" IsVisible="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ZIndex="99" PointerPressed="OnWarningPopupOverlayPointerPressed">
|
||||
<!-- Popup User Control -->
|
||||
|
||||
<!-- Module for Name Entry -->
|
||||
<Grid PointerPressed="" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="20" IsVisible="True">
|
||||
<Border Background="White" CornerRadius="10" Padding="20" BorderThickness="1" ZIndex="101" BorderBrush="#CCC">
|
||||
<StackPanel Spacing="15">
|
||||
<!-- Label for Text Input -->
|
||||
<!-- Label -->
|
||||
|
||||
|
||||
<TextBlock x:Name="warningTitel" Text="Warning"
|
||||
FontSize="20"
|
||||
FontWeight="Bold"
|
||||
Foreground="Red"
|
||||
Margin="0,0,0,8" />
|
||||
<StackPanel>
|
||||
<TextBlock x:Name="warningMsg" Text=""
|
||||
FontSize="20"
|
||||
FontWeight="Bold"
|
||||
Foreground="Black"
|
||||
Margin="0,0,0,8" />
|
||||
|
||||
</StackPanel>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Button Panel -->
|
||||
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
|
||||
|
||||
|
||||
</Window>
|
||||
4917
DaireApplication/Views/MainWindow.axaml.cs
Normal file
1517
DaireApplication/Views/UserController/Admin.axaml
Normal file
394
DaireApplication/Views/UserController/Admin.axaml.cs
Normal file
@@ -0,0 +1,394 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.Media;
|
||||
using AvaloniaApplication1.DataBase;
|
||||
using DaireApplication.DataBase;
|
||||
using DaireApplication.Views;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DaireApplication;
|
||||
|
||||
public partial class Admin : UserControl
|
||||
{
|
||||
private MainWindow? _mainWindow;
|
||||
private UserTable? _currentUser;
|
||||
private MachineTable _machine;
|
||||
private ConfigrationTable _configration;
|
||||
private CancellationTokenSource _cancellationTokenSource;
|
||||
private bool _isLongPress = false;
|
||||
public Admin()
|
||||
{
|
||||
InitializeComponent();
|
||||
_machine = new MachineTable();
|
||||
_machine = _machine.ReadMachine();
|
||||
}
|
||||
|
||||
public Admin(MainWindow mainWindow, UserTable currentUser)
|
||||
{
|
||||
_currentUser = currentUser;
|
||||
_mainWindow = mainWindow;
|
||||
_machine = new MachineTable();
|
||||
_machine = _machine.ReadMachine();
|
||||
_configration = new();
|
||||
|
||||
InitializeComponent();
|
||||
setDefaultSettings();
|
||||
setDafaultValues();
|
||||
AttachHandlers(_mainWindow.logoBtn, AdvanceSettingsView);
|
||||
AttachHandlers(_mainWindow.UserName, CloseApplication);
|
||||
_mainWindow.minimizeBtn.Click += MinimizeButton_Click;
|
||||
}
|
||||
public void AttachHandlers(Button button,System.EventHandler<Avalonia.Input.HoldingRoutedEventArgs> func)
|
||||
{
|
||||
if (button != null)
|
||||
{
|
||||
button.Holding += func;
|
||||
|
||||
button.PointerPressed += (sender, e) =>
|
||||
{
|
||||
// Simulate a long press on any pointer (mouse or touch)
|
||||
var point = e.GetPosition(button);
|
||||
func(sender, new HoldingRoutedEventArgs(HoldingState.Started, point, e.Pointer.Type));
|
||||
};
|
||||
|
||||
button.PointerReleased += (sender, e) =>
|
||||
{
|
||||
// End simulated long press
|
||||
var point = e.GetPosition(button);
|
||||
func(sender, new HoldingRoutedEventArgs(HoldingState.Completed, point, e.Pointer.Type));
|
||||
};
|
||||
}
|
||||
}
|
||||
private void MinimizeButton_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
_mainWindow.WindowState = Avalonia.Controls.WindowState.Minimized;
|
||||
}
|
||||
public static void CloseApplication(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var lifetime = Application.Current?.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime;
|
||||
lifetime?.Shutdown(); // This should correctly shut down the application
|
||||
}
|
||||
public void AdvanceSettingsView(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_mainWindow.ContentArea.Content== this )
|
||||
{
|
||||
_mainWindow.ContentArea.Content = new AdvanceSettings(_mainWindow);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
private async void changeValue(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Button button)
|
||||
{
|
||||
var gridParent = button.Parent as Grid;
|
||||
var stack = gridParent.Children[1] as StackPanel;
|
||||
var targetText = stack.Children[0] as TextBlock;
|
||||
|
||||
// Handle single click behavior (just increase or decrease by 1)
|
||||
int currentValue = int.TryParse(targetText.Text, out var value) ? value : 0;
|
||||
if (gridParent.Tag.ToString() != "pMint" && gridParent.Tag.ToString() != "aMint")
|
||||
{
|
||||
if (button.Content.ToString() == "+")
|
||||
{
|
||||
targetText.Text = (currentValue + 1).ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (currentValue>0)
|
||||
{
|
||||
targetText.Text = (currentValue - 1).ToString();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (button.Content.ToString() == "+")
|
||||
{
|
||||
if (currentValue<0)
|
||||
{
|
||||
targetText.Text = (currentValue + 1).ToString();
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
targetText.Text = (currentValue - 1).ToString();
|
||||
}
|
||||
}
|
||||
|
||||
// Perform machine updates based on the tag
|
||||
MachineTable data = _machine.ReadMachine();
|
||||
data.Id = _machine.Id;
|
||||
|
||||
if (gridParent.Tag.ToString() == "pMaxt")
|
||||
data.PumbMaxHeat = int.Parse(targetText.Text);
|
||||
else if (gridParent.Tag.ToString() == "pMint")
|
||||
data.PumbMinHeat = int.Parse(targetText.Text);
|
||||
else if (gridParent.Tag.ToString() == "tmt")
|
||||
data.TankMaxHeat = int.Parse(targetText.Text);
|
||||
else if (gridParent.Tag.ToString() == "pd")
|
||||
data.PumbDelay = int.Parse(targetText.Text);
|
||||
else if (gridParent.Tag.ToString() == "pht")
|
||||
data.PreHeatingTemp = int.Parse(targetText.Text);
|
||||
else if (gridParent.Tag.ToString() == "md")
|
||||
data.MixerDelay = int.Parse(targetText.Text);
|
||||
else if (gridParent.Tag.ToString() == "pouring")
|
||||
data.PouringDelay = int.Parse(targetText.Text);
|
||||
else if (gridParent.Tag.ToString() == "cooling")
|
||||
data.CoolingDelay = int.Parse(targetText.Text);
|
||||
else if (gridParent.Tag.ToString() == "heating")
|
||||
data.HeatingDelay = int.Parse(targetText.Text);
|
||||
else if (gridParent.Tag.ToString() == "aMaxt")
|
||||
{
|
||||
data.AbsMaxHeat = int.Parse(targetText.Text);
|
||||
var allConfigrations = _configration.ReadConfigrations();
|
||||
foreach (var item in allConfigrations)
|
||||
{
|
||||
item.Max = (int)data.AbsMaxHeat;
|
||||
_configration.UpdateConfigration(item);
|
||||
}
|
||||
_mainWindow.sendConfig = true;
|
||||
}
|
||||
else if (gridParent.Tag.ToString() == "aMint")
|
||||
{
|
||||
data.AbsMinHeat = int.Parse(targetText.Text);
|
||||
var coolingConfig = _configration.ReadConfigrationById("3");
|
||||
//var pumbConfig = _configration.ReadConfigrationById("4");
|
||||
coolingConfig.Min = (int)data.AbsMinHeat;
|
||||
_configration.UpdateConfigration(coolingConfig);
|
||||
//pumbConfig.Min = 0;
|
||||
//_configration.UpdateConfigration(pumbConfig);
|
||||
_mainWindow.sendConfig = true;
|
||||
}
|
||||
|
||||
_machine.UpdateMachine(data);
|
||||
_mainWindow._machine = _machine.ReadMachine();
|
||||
}
|
||||
else if (sender is Border border)
|
||||
{
|
||||
Button button1 = this.FindControl<Button>(border.Tag.ToString());
|
||||
var gridParent = button1.Parent as Grid;
|
||||
var stack = gridParent.Children[1] as StackPanel;
|
||||
var targetText = stack.Children[0] as TextBlock;
|
||||
|
||||
// Handle single click behavior (just increase or decrease by 1)
|
||||
int currentValue = int.TryParse(targetText.Text, out var value) ? value : 0;
|
||||
if (gridParent.Tag.ToString() != "pMint" && gridParent.Tag.ToString() != "aMint")
|
||||
{
|
||||
if (button1.Content.ToString() == "+")
|
||||
{
|
||||
targetText.Text = (currentValue + 1).ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (currentValue > 0)
|
||||
{
|
||||
targetText.Text = (currentValue - 1).ToString();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (button1.Content.ToString() == "+")
|
||||
{
|
||||
if (currentValue < 0)
|
||||
{
|
||||
targetText.Text = (currentValue + 1).ToString();
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
targetText.Text = (currentValue - 1).ToString();
|
||||
}
|
||||
}
|
||||
|
||||
// Perform machine updates based on the tag
|
||||
MachineTable data = _machine.ReadMachine();
|
||||
data.Id = _machine.Id;
|
||||
|
||||
if (gridParent.Tag.ToString() == "pMaxt")
|
||||
data.PumbMaxHeat = int.Parse(targetText.Text);
|
||||
else if (gridParent.Tag.ToString() == "pMint")
|
||||
data.PumbMinHeat = int.Parse(targetText.Text);
|
||||
else if (gridParent.Tag.ToString() == "tmt")
|
||||
data.TankMaxHeat = int.Parse(targetText.Text);
|
||||
else if (gridParent.Tag.ToString() == "pd")
|
||||
data.PumbDelay = int.Parse(targetText.Text);
|
||||
else if (gridParent.Tag.ToString() == "pht")
|
||||
data.PreHeatingTemp = int.Parse(targetText.Text);
|
||||
else if (gridParent.Tag.ToString() == "md")
|
||||
data.MixerDelay = int.Parse(targetText.Text);
|
||||
else if (gridParent.Tag.ToString() == "pouring")
|
||||
data.PouringDelay = int.Parse(targetText.Text);
|
||||
else if (gridParent.Tag.ToString() == "cooling")
|
||||
data.CoolingDelay = int.Parse(targetText.Text);
|
||||
else if (gridParent.Tag.ToString() == "heating")
|
||||
data.HeatingDelay = int.Parse(targetText.Text);
|
||||
else if (gridParent.Tag.ToString() == "aMaxt")
|
||||
{
|
||||
data.AbsMaxHeat = int.Parse(targetText.Text);
|
||||
var allConfigrations = _configration.ReadConfigrations();
|
||||
foreach (var item in allConfigrations)
|
||||
{
|
||||
item.Max = (int)data.AbsMaxHeat;
|
||||
_configration.UpdateConfigration(item);
|
||||
}
|
||||
_mainWindow.sendConfig = true;
|
||||
}
|
||||
else if (gridParent.Tag.ToString() == "aMint")
|
||||
{
|
||||
data.AbsMinHeat = int.Parse(targetText.Text);
|
||||
var coolingConfig = _configration.ReadConfigrationById("3");
|
||||
//var pumbConfig = _configration.ReadConfigrationById("4");
|
||||
coolingConfig.Min = (int)data.AbsMinHeat;
|
||||
_configration.UpdateConfigration(coolingConfig);
|
||||
//pumbConfig.Min = 0;
|
||||
//_configration.UpdateConfigration(pumbConfig);
|
||||
_mainWindow.sendConfig = true;
|
||||
}
|
||||
|
||||
_machine.UpdateMachine(data);
|
||||
_mainWindow._machine = _machine.ReadMachine();
|
||||
}
|
||||
}
|
||||
|
||||
// Handle holding event
|
||||
private async void OnLongRecipeClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (e is HoldingRoutedEventArgs args)
|
||||
{
|
||||
if (args.HoldingState == HoldingState.Started)
|
||||
{
|
||||
_isLongPress = true;
|
||||
|
||||
if (sender is Button button)
|
||||
{
|
||||
var gridParent = button.Parent as Grid;
|
||||
var stack = gridParent.Children[1] as StackPanel;
|
||||
var targetText = stack.Children[0] as TextBlock;
|
||||
await ChangeValueRapidly(button.Content.ToString()=="+", targetText); // Start rapid increase
|
||||
args.Handled = true;
|
||||
}
|
||||
else if(sender is Border border)
|
||||
{
|
||||
Button button1 = this.FindControl<Button>(border.Tag.ToString());
|
||||
|
||||
var gridParent = button1.Parent as Grid;
|
||||
var stack = gridParent.Children[1] as StackPanel;
|
||||
var targetText = stack.Children[0] as TextBlock;
|
||||
await ChangeValueRapidly(button1.Content.ToString() == "+", targetText); // Start rapid increase
|
||||
args.Handled = true;
|
||||
}
|
||||
}
|
||||
else if (args.HoldingState == HoldingState.Completed || args.HoldingState == HoldingState.Cancelled)
|
||||
{
|
||||
_isLongPress = false;
|
||||
|
||||
// Stop the rapid value change when the holding is completed
|
||||
_cancellationTokenSource?.Cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ChangeValueRapidly(bool isIncrease, TextBlock targetText)
|
||||
{
|
||||
// Start rapid value change when the button is held
|
||||
_cancellationTokenSource?.Cancel(); // Cancel any previous task
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
var token = _cancellationTokenSource.Token;
|
||||
int currentValue = 0;
|
||||
|
||||
while (!token.IsCancellationRequested)
|
||||
{
|
||||
currentValue = int.TryParse(targetText.Text, out var value) ? value : 0;
|
||||
|
||||
if (targetText.Name!= "fountainMinTemp" && targetText.Name != "absMinTemp")
|
||||
{
|
||||
if (isIncrease)
|
||||
{
|
||||
targetText.Text = (currentValue + 1).ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (currentValue>0)
|
||||
{
|
||||
targetText.Text = (currentValue -1).ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isIncrease)
|
||||
{
|
||||
if (currentValue < 0)
|
||||
{
|
||||
targetText.Text = (currentValue + 1).ToString();
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
targetText.Text = (currentValue - 1).ToString();
|
||||
}
|
||||
}
|
||||
await Task.Delay(150); // Change speed here
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void setDafaultValues()
|
||||
{
|
||||
fountainMaxTemp.Text = _machine.PumbMaxHeat.ToString();
|
||||
tankMaxTemp.Text = _machine.TankMaxHeat.ToString();
|
||||
pumbDelay.Text = _machine.PumbDelay.ToString();
|
||||
mixerDelay.Text = _machine.MixerDelay.ToString();
|
||||
heatingPause.Text = _machine.HeatingDelay.ToString();
|
||||
coolingPause.Text = _machine.CoolingDelay.ToString();
|
||||
pouringPause.Text = _machine.PouringDelay.ToString();
|
||||
fountainMinTemp.Text=_machine.PumbMinHeat.ToString();
|
||||
absMaxTemp.Text= _machine.AbsMaxHeat.ToString();
|
||||
absMinTemp.Text= _machine.AbsMinHeat.ToString();
|
||||
preHeatingTemp.Text= _machine.PreHeatingTemp.ToString();
|
||||
}
|
||||
private void setDefaultSettings()
|
||||
{
|
||||
_mainWindow.minimizeBtn.IsVisible = true;
|
||||
//Set Track Up
|
||||
_mainWindow.HomeTrack.IsVisible = true;
|
||||
//_mainWindow.HomePolygon.Stroke = Avalonia.Media.Brushes.Black;
|
||||
_mainWindow.RecipeSelTrack.IsVisible = false;
|
||||
_mainWindow.RunInterfaceTrack.IsVisible = false;
|
||||
_mainWindow.RecipePanelTrack.IsVisible = false;
|
||||
_mainWindow.RecipeEditTrack.IsVisible = false;
|
||||
_mainWindow.DiagnosticsTrack.IsVisible = false;
|
||||
_mainWindow.AdvanceSettingsTrack.IsVisible = false;
|
||||
_mainWindow.SoftwareTrack.IsVisible = false;
|
||||
_mainWindow.SettingTrack.IsVisible = true;
|
||||
_mainWindow.SettingPolygon.Stroke = Brush.Parse("#A4275D"); ;
|
||||
_mainWindow.TitleBtn.IsVisible = false;
|
||||
//_mainWindow.Title.Text = _recipeTable.Name;
|
||||
|
||||
//Set Footer
|
||||
_mainWindow.footerMsg.IsVisible = false;
|
||||
_mainWindow.footer.Background = Avalonia.Media.Brushes.WhiteSmoke;
|
||||
_mainWindow.footerDate.Text = DateTime.Now.ToString("dd/MM/yyyy");
|
||||
_mainWindow.footerTime.Text = DateTime.Now.ToString("hh:mm tt");
|
||||
_mainWindow.footerDateContainer.IsVisible = true;
|
||||
_mainWindow.footerStartBtn.IsVisible = false;
|
||||
_mainWindow.adminBtns.IsVisible = true;
|
||||
_mainWindow.version.IsVisible = true;
|
||||
|
||||
}
|
||||
}
|
||||
1391
DaireApplication/Views/UserController/AdvanceSettings.axaml
Normal file
1077
DaireApplication/Views/UserController/AdvanceSettings.axaml.cs
Normal file
2393
DaireApplication/Views/UserController/Diagnostics.axaml
Normal file
1037
DaireApplication/Views/UserController/Diagnostics.axaml.cs
Normal file
140
DaireApplication/Views/UserController/Home.axaml
Normal file
@@ -0,0 +1,140 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
|
||||
x:Class="DaireApplication.Home"
|
||||
Width="1280" Height="620" >
|
||||
|
||||
|
||||
<Grid RowDefinitions="*">
|
||||
<!--Main Body-->
|
||||
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,*" >
|
||||
<Grid Grid.Column="1" HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center" Height="698" Width="465" >
|
||||
<Grid x:Name="machinePic" IsVisible="True">
|
||||
<Grid.Background >
|
||||
<ImageBrush Source="/Assets/Machine.png"/>
|
||||
</Grid.Background>
|
||||
</Grid>
|
||||
|
||||
<Grid x:Name="CalcGrid" MaxWidth="350" MaxHeight="500" IsVisible="False">
|
||||
<Grid.Styles>
|
||||
|
||||
<Style Selector="Button">
|
||||
<Setter Property="Background" Value="White"></Setter>
|
||||
<Setter Property="CornerRadius" Value="20"></Setter>
|
||||
<Setter Property="Width" Value="100"></Setter>
|
||||
<Setter Property="Height" Value="100"></Setter>
|
||||
<Setter Property="FontSize" Value="50"></Setter>
|
||||
<Setter Property="Foreground" Value="Black"></Setter>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"></Setter>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Center"></Setter>
|
||||
|
||||
</Style>
|
||||
<Style Selector="Button:pointerover /template/ContentPresenter">
|
||||
<Setter Property="Foreground" Value="Black"></Setter>
|
||||
<Setter Property="Background" Value="White"></Setter>
|
||||
<Setter Property="CornerRadius" Value="20"></Setter>
|
||||
<Setter Property="RenderTransform" Value="scale(1.11)"></Setter>
|
||||
|
||||
</Style>
|
||||
|
||||
|
||||
</Grid.Styles>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- TextBox for Input -->
|
||||
<TextBox x:Name="InputTextBox" Grid.Row="0" Width="300" Height="50" FontSize="20" HorizontalAlignment="Center" Margin="10" IsReadOnly="True" PasswordChar="*"/>
|
||||
|
||||
|
||||
<!-- Keypad Grid -->
|
||||
<Grid Grid.Row="1" Margin="10">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="1*" />
|
||||
<RowDefinition Height="1*" />
|
||||
<RowDefinition Height="1*" />
|
||||
<RowDefinition Height="1*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Number Buttons -->
|
||||
<Button Content="1" Grid.Row="0" Grid.Column="0" FontSize="24" Background="White" Margin="5" Click="OnKeyClick" />
|
||||
<Button Content="2" Grid.Row="0" Grid.Column="1" FontSize="24" Background="White" Margin="5" Click="OnKeyClick" />
|
||||
<Button Content="3" Grid.Row="0" Grid.Column="2" FontSize="24" Background="White" Margin="5" Click="OnKeyClick" />
|
||||
|
||||
<Button Content="4" Grid.Row="1" Grid.Column="0" FontSize="24" Background="White" Margin="5" Click="OnKeyClick" />
|
||||
<Button Content="5" Grid.Row="1" Grid.Column="1" FontSize="24" Background="White" Margin="5" Click="OnKeyClick" />
|
||||
<Button Content="6" Grid.Row="1" Grid.Column="2" FontSize="24" Background="White" Margin="5" Click="OnKeyClick" />
|
||||
|
||||
<Button Content="7" Grid.Row="2" Grid.Column="0" FontSize="24" Background="White" Margin="5" Click="OnKeyClick" />
|
||||
<Button Content="8" Grid.Row="2" Grid.Column="1" FontSize="24" Background="White" Margin="5" Click="OnKeyClick" />
|
||||
<Button Content="9" Grid.Row="2" Grid.Column="2" FontSize="24" Background="White" Margin="5" Click="OnKeyClick" />
|
||||
|
||||
<!-- Control Buttons -->
|
||||
<Button Content="BACK" Grid.Row="3" Grid.Column="0" FontSize="20" Background="#D3D3D3" Margin="5" Click="OnBackClick" />
|
||||
<Button Content="0" Grid.Row="3" Grid.Column="1" FontSize="24" Background="White" Margin="5" Click="OnKeyClick" />
|
||||
<Button x:Name="loginBtn" Content="ENTER" Grid.Row="3" Grid.Column="2" FontSize="20" Background="#A4275D" Foreground="White" Margin="5" Click="LogIn" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
|
||||
|
||||
</Grid>
|
||||
<Grid Grid.Column="0" RowDefinitions="Auto,1.5*">
|
||||
<StackPanel Margin="10,50,0,10" Grid.Row="0" HorizontalAlignment="Center" >
|
||||
<Label Foreground="Black" FontSize="30" FontWeight="Normal" >USER SELECTION</Label>
|
||||
</StackPanel>
|
||||
<ScrollViewer Grid.Row="1" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" Margin="0,0">
|
||||
<Grid x:Name="DynamicGrid">
|
||||
<!-- Define three columns -->
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid.Styles>
|
||||
|
||||
|
||||
<Style Selector="Button">
|
||||
<Setter Property="Background" Value="White"></Setter>
|
||||
</Style>
|
||||
|
||||
<Style Selector="Button:pointerover /template/ContentPresenter">
|
||||
<Setter Property="RenderTransform" Value="scale(1.11)"></Setter>
|
||||
<Setter Property="Background" Value="White"></Setter>
|
||||
|
||||
|
||||
</Style>
|
||||
|
||||
|
||||
</Grid.Styles>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Dynamic rows will be generated programmatically in code-behind -->
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
|
||||
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
|
||||
|
||||
|
||||
|
||||
</UserControl>
|
||||
755
DaireApplication/Views/UserController/Home.axaml.cs
Normal file
@@ -0,0 +1,755 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Shapes;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Media;
|
||||
using AvaloniaApplication1.DataBase;
|
||||
using DaireApplication.DataBase;
|
||||
using DaireApplication.Views;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace DaireApplication;
|
||||
|
||||
public partial class Home : UserControl
|
||||
{
|
||||
private Button? _previousButton;
|
||||
private Button? currentButton;
|
||||
private UserTable _userRepo = new UserTable();
|
||||
private MainWindow? _mainWindow;
|
||||
|
||||
public Home()
|
||||
{
|
||||
|
||||
|
||||
|
||||
}
|
||||
public Home(MainWindow mainWindow)
|
||||
{
|
||||
_mainWindow = mainWindow;
|
||||
InitializeComponent();
|
||||
|
||||
// Migrate legacy data to AppData directory
|
||||
DataPathManager.MigrateLegacyData();
|
||||
|
||||
setDefaultSettings();
|
||||
setDefaultUsers();
|
||||
setDefaultRecipe();
|
||||
setDefaultMachine();
|
||||
SetDefaultMapping();
|
||||
SetDefaultConfigration();
|
||||
SetDefaultScreen();
|
||||
SetDefaultErrorSettings();
|
||||
|
||||
addDynamicButtons();
|
||||
_mainWindow.UserName.Holding -= Admin.CloseApplication;
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
private async void OnUserButtonClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Button button) // Ensure the sender is the button that triggered the event
|
||||
{
|
||||
currentButton = button;
|
||||
if (_previousButton != null)
|
||||
{
|
||||
if (_previousButton == button)
|
||||
{
|
||||
if (button.Tag == "1")
|
||||
{
|
||||
CalcGrid.IsVisible = !CalcGrid.IsVisible;
|
||||
machinePic.IsVisible = !machinePic.IsVisible;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
loginBtn.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
ResetButtonColor(_previousButton);
|
||||
|
||||
}
|
||||
var textBlock = button.Content as TextBlock;
|
||||
|
||||
if (textBlock != null)
|
||||
{
|
||||
textBlock.Foreground = Avalonia.Media.Brushes.DeepPink;
|
||||
}
|
||||
button.BorderBrush = Avalonia.Media.Brushes.DeepPink;
|
||||
button.BorderThickness = new Thickness(3);
|
||||
_previousButton = button;
|
||||
if (button.Tag == "1")
|
||||
{
|
||||
CalcGrid.IsVisible = !CalcGrid.IsVisible;
|
||||
machinePic.IsVisible = !machinePic.IsVisible;
|
||||
}
|
||||
else
|
||||
{
|
||||
loginBtn.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));
|
||||
|
||||
}
|
||||
//CalcGrid.IsVisible = !CalcGrid.IsVisible;
|
||||
//machinePic.IsVisible = !machinePic.IsVisible;
|
||||
|
||||
|
||||
}
|
||||
|
||||
//End UI...
|
||||
|
||||
}
|
||||
|
||||
private void LogIn(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Button button)
|
||||
{
|
||||
|
||||
var users = _userRepo.ReadUsers();
|
||||
string inputText = InputTextBox.Text;
|
||||
foreach (var item in users)
|
||||
{
|
||||
if (currentButton.Content is Grid grid)
|
||||
{
|
||||
if (grid.Children[0] is TextBlock textBlock)
|
||||
{
|
||||
if (textBlock.Text == item.UserName)
|
||||
{
|
||||
if (item.IsActive)
|
||||
{
|
||||
if (inputText == item.Password)
|
||||
{
|
||||
var userName = _mainWindow.FindControl<Button>("UserName");
|
||||
userName.Content = item.UserName;
|
||||
Program.currentUser = item;
|
||||
if (item.IsAdmin == true)
|
||||
{
|
||||
_mainWindow.holdingRegister.resetError = 0;
|
||||
|
||||
_mainWindow.restBoard = true;
|
||||
|
||||
_mainWindow.FindControl<ContentControl>("ContentArea").Content = new Admin(_mainWindow, item);
|
||||
return;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
_mainWindow.FindControl<ContentControl>("ContentArea").Content = new Recipe(_mainWindow, item);
|
||||
|
||||
|
||||
InputTextBox.Text = string.Empty;
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
_mainWindow.TextCenter.HorizontalAlignment = HorizontalAlignment.Center;
|
||||
_mainWindow.footerMsg.Text = "Wrong Password!!";
|
||||
_mainWindow.footerMsg.IsVisible = true;
|
||||
_mainWindow.footer.Background = Avalonia.Media.Brushes.Red;
|
||||
_mainWindow.footerMsg.Foreground = Avalonia.Media.Brushes.White;
|
||||
_mainWindow.footerMsg.HorizontalAlignment = HorizontalAlignment.Center;
|
||||
_mainWindow.footerDateContainer.IsVisible = false;
|
||||
_mainWindow.footerStartBtn.IsVisible = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var userName = _mainWindow.FindControl<Button>("UserName");
|
||||
userName.Content = item.UserName;
|
||||
Program.currentUser = item;
|
||||
if (item.IsAdmin == true)
|
||||
{
|
||||
_mainWindow.holdingRegister.resetError = 0;
|
||||
_mainWindow.restBoard = true;
|
||||
|
||||
_mainWindow.FindControl<ContentControl>("ContentArea").Content = new Admin(_mainWindow, item);
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
_mainWindow.FindControl<ContentControl>("ContentArea").Content = new Recipe(_mainWindow, item);
|
||||
|
||||
|
||||
InputTextBox.Text = string.Empty;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Display or use the input text
|
||||
|
||||
// Clear the text after showing the message
|
||||
InputTextBox.Text = string.Empty;
|
||||
}
|
||||
|
||||
private void OnKeyClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Button button)
|
||||
{
|
||||
// Append the button's content to the input box
|
||||
InputTextBox.Text += button.Content?.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
private void OnBackClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(InputTextBox.Text))
|
||||
{
|
||||
// Remove the last character from the text box
|
||||
InputTextBox.Text = InputTextBox.Text.Remove(InputTextBox.Text.Length - 1);
|
||||
}
|
||||
}
|
||||
private void ResetButtonColor(Button button)
|
||||
{
|
||||
button.BorderBrush = Avalonia.Media.Brushes.White;
|
||||
|
||||
var textBlock = button.Content as TextBlock;
|
||||
|
||||
if (textBlock != null)
|
||||
{
|
||||
textBlock.Foreground = Avalonia.Media.Brushes.Black;
|
||||
}
|
||||
// Reset the color of the TextBlock inside the button
|
||||
}
|
||||
|
||||
|
||||
private void addDynamicButtons()
|
||||
{
|
||||
var users = _userRepo.ReadUsers();
|
||||
var grid = this.FindControl<Grid>("DynamicGrid");
|
||||
int userIdex = 0;
|
||||
if (users.Count < 2)
|
||||
{
|
||||
for (int i = 0; i < (int)Math.Ceiling((double)users.Count / 2); i++) // Example: 20 rows
|
||||
{
|
||||
grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
|
||||
|
||||
// Add content for each column
|
||||
for (int col = 0; col < 2; col++)
|
||||
{
|
||||
// StackPanel for the LED indicator dots
|
||||
var indicatorPanel = new StackPanel
|
||||
{
|
||||
Orientation = Orientation.Horizontal,
|
||||
HorizontalAlignment = HorizontalAlignment.Center,
|
||||
Margin = new Thickness(10),
|
||||
Spacing = 10
|
||||
};
|
||||
|
||||
// Adding the indicator dots dynamically
|
||||
if (users[userIdex + col].IsAdmin)
|
||||
{
|
||||
var colors = new[] { Brush.Parse("#A4275D"), Brush.Parse("#A4275D"), Brush.Parse("#A4275D") };
|
||||
foreach (var color in colors)
|
||||
{
|
||||
indicatorPanel.Children.Add(new Rectangle
|
||||
{
|
||||
Width = 30,
|
||||
Height = 10,
|
||||
Fill = color,
|
||||
RadiusX = 3,
|
||||
RadiusY = 3,
|
||||
Margin = new Thickness(3),
|
||||
VerticalAlignment = VerticalAlignment.Bottom,
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (users[userIdex + col].CanEdit)
|
||||
{
|
||||
var colors = new[] { Brush.Parse("#A4275D"), Brush.Parse("#A4275D") };
|
||||
foreach (var color in colors)
|
||||
{
|
||||
indicatorPanel.Children.Add(new Rectangle
|
||||
{
|
||||
Width = 30,
|
||||
Height = 10,
|
||||
Fill = color,
|
||||
RadiusX = 3,
|
||||
RadiusY = 3,
|
||||
Margin = new Thickness(3),
|
||||
VerticalAlignment = VerticalAlignment.Bottom,
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var colors = new[] { Brush.Parse("#A4275D") };
|
||||
foreach (var color in colors)
|
||||
{
|
||||
indicatorPanel.Children.Add(new Rectangle
|
||||
{
|
||||
Width = 30,
|
||||
Height = 10,
|
||||
Fill = color,
|
||||
RadiusX = 3,
|
||||
RadiusY = 3,
|
||||
Margin = new Thickness(3),
|
||||
VerticalAlignment = VerticalAlignment.Bottom,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Create a Grid for button content with two rows:
|
||||
// Row 0 (star) holds the text (centered) and Row 1 (auto) holds the indicator dots at the bottom.
|
||||
var buttonContent = new Grid();
|
||||
buttonContent.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
|
||||
buttonContent.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
|
||||
|
||||
// TextBlock centered in first row
|
||||
var textBlock = new TextBlock
|
||||
{
|
||||
Padding = new Thickness(10),
|
||||
Text = users[userIdex + col].UserName,
|
||||
FontSize = 40,
|
||||
FontWeight = FontWeight.Normal,
|
||||
Foreground = Avalonia.Media.Brushes.Black,
|
||||
HorizontalAlignment = HorizontalAlignment.Center,
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
};
|
||||
|
||||
// Place the text in the first row
|
||||
Grid.SetRow(textBlock, 0);
|
||||
// Place the indicator panel in the second row
|
||||
Grid.SetRow(indicatorPanel, 1);
|
||||
|
||||
// Add both elements to the grid
|
||||
buttonContent.Children.Add(textBlock);
|
||||
buttonContent.Children.Add(indicatorPanel);
|
||||
|
||||
// Create the button with the new content layout
|
||||
var button = new Button
|
||||
{
|
||||
Width = 290,
|
||||
Height = 190,
|
||||
Margin = new Thickness(10),
|
||||
Content = buttonContent,
|
||||
Tag = users[userIdex + col].IsActive ? "1" : "0",
|
||||
CornerRadius = new CornerRadius(10),
|
||||
Background = Avalonia.Media.Brushes.White,
|
||||
HorizontalAlignment = HorizontalAlignment.Center,
|
||||
VerticalAlignment = VerticalAlignment.Bottom,
|
||||
};
|
||||
|
||||
button.Click += OnUserButtonClick;
|
||||
grid.Children.Add(button);
|
||||
Grid.SetRow(button, i);
|
||||
Grid.SetColumn(button, col);
|
||||
}
|
||||
userIdex += 2;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < (int)Math.Ceiling((double)users.Count / 2); i++) // Example: 20 rows
|
||||
{
|
||||
grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
|
||||
|
||||
// Add content for each column
|
||||
for (int col = 0; col < 2; col++)
|
||||
{
|
||||
// StackPanel for the LED indicator dots
|
||||
var indicatorPanel = new StackPanel
|
||||
{
|
||||
Orientation = Orientation.Horizontal,
|
||||
HorizontalAlignment = HorizontalAlignment.Center,
|
||||
Margin = new Thickness(10),
|
||||
Spacing = 10
|
||||
};
|
||||
|
||||
// Adding the indicator dots dynamically
|
||||
if (users[userIdex + col].IsAdmin)
|
||||
{
|
||||
var colors = new[] { Brush.Parse("#A4275D"), Brush.Parse("#A4275D"), Brush.Parse("#A4275D") };
|
||||
foreach (var color in colors)
|
||||
{
|
||||
indicatorPanel.Children.Add(new Rectangle
|
||||
{
|
||||
Width = 30,
|
||||
Height = 10,
|
||||
Fill = color,
|
||||
RadiusX = 3,
|
||||
RadiusY = 3,
|
||||
Margin = new Thickness(3),
|
||||
VerticalAlignment = VerticalAlignment.Bottom,
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (users[userIdex + col].CanEdit)
|
||||
{
|
||||
var colors = new[] { Brush.Parse("#A4275D"), Brush.Parse("#A4275D") };
|
||||
foreach (var color in colors)
|
||||
{
|
||||
indicatorPanel.Children.Add(new Rectangle
|
||||
{
|
||||
Width = 30,
|
||||
Height = 10,
|
||||
Fill = color,
|
||||
RadiusX = 3,
|
||||
RadiusY = 3,
|
||||
Margin = new Thickness(3),
|
||||
VerticalAlignment = VerticalAlignment.Bottom,
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var colors = new[] { Brush.Parse("#A4275D") };
|
||||
foreach (var color in colors)
|
||||
{
|
||||
indicatorPanel.Children.Add(new Rectangle
|
||||
{
|
||||
Width = 30,
|
||||
Height = 10,
|
||||
Fill = color,
|
||||
RadiusX = 3,
|
||||
RadiusY = 3,
|
||||
Margin = new Thickness(3),
|
||||
VerticalAlignment = VerticalAlignment.Bottom,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Create a Grid for button content with two rows:
|
||||
// Row 0 (star) holds the text (centered) and Row 1 (auto) holds the indicator dots at the bottom.
|
||||
var buttonContent = new Grid();
|
||||
buttonContent.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
|
||||
buttonContent.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
|
||||
|
||||
// TextBlock centered in first row
|
||||
var textBlock = new TextBlock
|
||||
{
|
||||
Padding = new Thickness(10),
|
||||
Text = users[userIdex + col].UserName,
|
||||
FontSize = 40,
|
||||
FontWeight = FontWeight.Normal,
|
||||
Foreground = Avalonia.Media.Brushes.Black,
|
||||
HorizontalAlignment = HorizontalAlignment.Center,
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
};
|
||||
|
||||
// Place the text in the first row
|
||||
Grid.SetRow(textBlock, 0);
|
||||
// Place the indicator panel in the second row
|
||||
Grid.SetRow(indicatorPanel, 1);
|
||||
|
||||
// Add both elements to the grid
|
||||
buttonContent.Children.Add(textBlock);
|
||||
buttonContent.Children.Add(indicatorPanel);
|
||||
|
||||
// Create the button with the new content layout
|
||||
var button = new Button
|
||||
{
|
||||
Width = 290,
|
||||
Height = 190,
|
||||
Margin = new Thickness(10),
|
||||
Tag = users[userIdex + col].IsActive ? "1" : "0",
|
||||
Content = buttonContent,
|
||||
CornerRadius = new CornerRadius(10),
|
||||
Background = Avalonia.Media.Brushes.White,
|
||||
HorizontalAlignment = HorizontalAlignment.Center,
|
||||
VerticalAlignment = VerticalAlignment.Bottom,
|
||||
};
|
||||
|
||||
button.Click += OnUserButtonClick;
|
||||
grid.Children.Add(button);
|
||||
Grid.SetRow(button, i);
|
||||
Grid.SetColumn(button, col);
|
||||
}
|
||||
userIdex += 2;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void setDefaultUsers()
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("Users.csv");
|
||||
List<UserTable> users = new List<UserTable>();
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
string csvHeader = "ID,UserName,Password,CanEdit,IsAdmin,IsActive";
|
||||
|
||||
users.Add(new UserTable
|
||||
{
|
||||
Id = 1,
|
||||
UserName = "ADMIN",
|
||||
Password = "1111",
|
||||
CanEdit = true,
|
||||
IsAdmin = true,
|
||||
IsActive = false
|
||||
}
|
||||
);
|
||||
users.Add(new UserTable
|
||||
{
|
||||
Id = 2,
|
||||
UserName = "CHEF",
|
||||
Password = "2222",
|
||||
CanEdit = true,
|
||||
IsAdmin = false,
|
||||
IsActive = false
|
||||
|
||||
}
|
||||
);
|
||||
users.Add(new UserTable
|
||||
{
|
||||
Id = 3,
|
||||
UserName = "OPERATOR1",
|
||||
Password = "3333",
|
||||
CanEdit = false,
|
||||
IsAdmin = false,
|
||||
IsActive = false
|
||||
|
||||
|
||||
}
|
||||
);
|
||||
users.Add(new UserTable
|
||||
{
|
||||
Id = 4,
|
||||
UserName = "OPERATOR2",
|
||||
Password = "4444",
|
||||
CanEdit = false,
|
||||
IsAdmin = false,
|
||||
IsActive = false
|
||||
|
||||
|
||||
}
|
||||
);
|
||||
List<string> lines = new List<string>();
|
||||
foreach (var item in users)
|
||||
{
|
||||
lines.Add(string.Join(",", [item.Id, item.UserName, item.Password, item.CanEdit ? "1" : "0", item.IsAdmin ? "1" : "0", item.IsActive ? "1" : "0"]));
|
||||
}
|
||||
File.WriteAllLines(filePath, new string[] { csvHeader });
|
||||
File.AppendAllLines(filePath, lines);
|
||||
}
|
||||
}
|
||||
|
||||
private void setDefaultRecipe()
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("Recipe.csv");
|
||||
List<RecipeTable> recipes = new List<RecipeTable>();
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
string csvHeader = "ID,Name,TankTemp,FountainTemp,Mixer,Fountain,MoldHeater,Vibration,VibHeater,Pedal,PedalOnTime,PedalOffTime,HeatingGoal,CoolingGoal,PouringGoal";
|
||||
|
||||
recipes.Add(new RecipeTable
|
||||
{
|
||||
Id = 1,
|
||||
Name = "MILK",
|
||||
Mixer = false,
|
||||
Fountain = false,
|
||||
MoldHeater = false,
|
||||
Vibration = false,
|
||||
VibHeater = false,
|
||||
Pedal = false
|
||||
|
||||
}
|
||||
);
|
||||
List<string> lines = new List<string>();
|
||||
foreach (var item in recipes)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
lines.Add(string.Join(",", [1, item.Name, item.TankTemp, item.FountainTemp, item.Mixer.Value ? "1" : "0", item.Fountain.Value ? "1" : "0", item.MoldHeater.Value ? "1" : "0", item.Vibration.Value ? "1" : "0", item.VibHeater.Value ? "1" : "0", item.Pedal.Value ? "1" : "0", item.PedalOnTime, item.PedalOffTime, item.HeatingGoal, item.CoolingGoal, item.PouringGoal]));
|
||||
}
|
||||
}
|
||||
|
||||
File.WriteAllLines(filePath, new string[] { csvHeader });
|
||||
File.AppendAllLines(filePath, lines);
|
||||
}
|
||||
}
|
||||
|
||||
private void setDefaultMachine()
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("Machine.csv");
|
||||
MachineTable machine = new MachineTable();
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
string csvHeader = "ID,TankMaxHeat,PumbMaxHeat,PumbDelay,MixerDelay,HeatingDelay,CoolingDelay,PouringDelay,PumbMinHeat,AbsMaxTemp,AbsMinTemp,PreHeatingTemp,SetTemp1,SetTemp2,SetTemp3,SetTemp4";
|
||||
|
||||
string line = string.Join(",", ["1", machine.TankMaxHeat, machine.PumbMaxHeat, machine.PumbDelay, machine.MixerDelay, machine.HeatingDelay, machine.CoolingDelay, machine.PouringDelay, machine.PumbMinHeat, machine.AbsMaxHeat, machine.AbsMinHeat, machine.PreHeatingTemp, machine.setTemp1, machine.setTemp2, machine.setTemp3, machine.setTemp4]);
|
||||
|
||||
File.WriteAllLines(filePath, new string[] { csvHeader });
|
||||
File.AppendAllText(filePath, line);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void SetDefaultMapping()
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("Mapping.csv");
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
string csvHeader = "Id,Name,Address,IsRead,BitNumbers";
|
||||
|
||||
string[] defaultMappings =
|
||||
{
|
||||
string.Join(",", "1", "Pedal", "1", "1", "0"),
|
||||
string.Join(",", "2", "Cover Sensor", "1", "1", "1"),
|
||||
string.Join(",", "3", "E-Stop", "1", "1", "2"),
|
||||
string.Join(",", "4", "Tank Bottom Temp", "8", "1", "8"),
|
||||
string.Join(",", "5", "Tank Wall Temp", "9", "1", "9"),
|
||||
string.Join(",", "6", "Pump Temp", "10", "1", "10"),
|
||||
string.Join(",", "7", "Fountain Temp", "11", "1", "11"),
|
||||
string.Join(",", "8", "Vibrator Heater", "2", "0", "0"),
|
||||
string.Join(",", "9", "Mold Heater", "2", "0", "1"),
|
||||
string.Join(",", "10", "Alarm", "2", "0", "2"),
|
||||
string.Join(",", "11", "Vibrator", "1", "0", "0"),
|
||||
string.Join(",", "12", "Water", "1", "0", "1"),
|
||||
string.Join(",", "13", "Compressor", "1", "0", "2"),
|
||||
string.Join(",", "14", "HELIX Heater", "1", "0", "3"),
|
||||
string.Join(",", "15", "Tank Heater Bottom", "1", "0", "4"),
|
||||
string.Join(",", "16", "Tank Heater Wall", "1", "0", "5"),
|
||||
string.Join(",", "17", "Mixer", "3", "0", "0"),
|
||||
string.Join(",", "18", "Helix", "3", "0", "1")
|
||||
};
|
||||
|
||||
File.WriteAllLines(filePath, new[] { csvHeader }.Concat(defaultMappings));
|
||||
}
|
||||
}
|
||||
|
||||
private void SetDefaultConfigration()
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("Configration.csv");
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
string csvHeader = "Id,Max,Min,H_out,FC_out,SC_out,kp,ki,kd,kl,Name,I_Nuet,I_Mot1,I_Mot2,FC_Threshold,HeatConRange";
|
||||
|
||||
string[] defaultConfigrations =
|
||||
{
|
||||
string.Join(",", "1", $"70", "0", "4", "-1", "-1", "50", "30", "20", "0","Tank Heater Bottom","14","3","3","0.3","10.0"),
|
||||
string.Join(",", "2", $"70", "0", "5", "-1", "-1", "50", "30", "20", "0","Tank Heater Wall","0","0","0","0.3","10.0"),
|
||||
string.Join(",", "3", $"70", $"-10", "3", "2|1", "1", "50", "30", "20", "0","HELIX Heater","0","0","0","0.3","10.0"),
|
||||
string.Join(",", "4", $"70", "0", "3", "2|1", "1", "50", "30", "20", "0","","0","0","0","0.3","5")
|
||||
};
|
||||
|
||||
File.WriteAllLines(filePath, new[] { csvHeader }.Concat(defaultConfigrations));
|
||||
}
|
||||
}
|
||||
|
||||
private void setDefaultSettings()
|
||||
{
|
||||
_mainWindow.minimizeBtn.IsVisible = false;
|
||||
|
||||
//Set Track Up
|
||||
_mainWindow.HomeTrack.IsVisible = true;
|
||||
//_mainWindow.HomePolygon.Stroke = Brush.Parse("#A4275D");
|
||||
_mainWindow.RecipeSelTrack.IsVisible = false;
|
||||
_mainWindow.RecipeEditTrack.IsVisible = false;
|
||||
_mainWindow.RecipePanelTrack.IsVisible = false;
|
||||
_mainWindow.RunInterfaceTrack.IsVisible = false;
|
||||
_mainWindow.SettingTrack.IsVisible = false;
|
||||
_mainWindow.TitleBtn.IsVisible = false;
|
||||
_mainWindow.DiagnosticsTrack.IsVisible = false;
|
||||
_mainWindow.AdvanceSettingsTrack.IsVisible = false;
|
||||
_mainWindow.SoftwareTrack.IsVisible = false;
|
||||
_mainWindow.version.IsVisible = false;
|
||||
_mainWindow.ManualControlTrack.IsVisible = false;
|
||||
|
||||
|
||||
|
||||
|
||||
//Set Footer
|
||||
_mainWindow.footerMsg.Text = "";
|
||||
_mainWindow.footerMsg.MaxWidth = 1000;
|
||||
_mainWindow.footer.Background = Avalonia.Media.Brushes.WhiteSmoke;
|
||||
_mainWindow.footerMsg.Foreground = Avalonia.Media.Brushes.Black;
|
||||
_mainWindow.footerDate.Text = DateTime.Now.ToString("dd/MM/yyyy");
|
||||
_mainWindow.footerTime.Text = DateTime.Now.ToString("hh:mm tt");
|
||||
_mainWindow.footerDateContainer.IsVisible = true;
|
||||
_mainWindow.footerStartBtn.IsVisible = false;
|
||||
_mainWindow.adminBtns.IsVisible = false;
|
||||
_mainWindow.chefBtns.IsVisible = false;
|
||||
|
||||
}
|
||||
|
||||
private void SetDefaultErrorSettings()
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("ErrorSettings.csv");
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
ErrorSettingsTable error = new ErrorSettingsTable
|
||||
{
|
||||
Id = 1,
|
||||
gridFreq = 50,
|
||||
phaseNumber = 3,
|
||||
extPower = true,
|
||||
phaseVoltage = 220
|
||||
};
|
||||
|
||||
string csvHeader = "Id,gridFreq,phaseNumber,extPower,phaseVoltage";
|
||||
string line = string.Join(",", new[] { error.Id.ToString(), error.gridFreq.ToString(), error.phaseNumber.ToString(), error.extPower ? "1" : "0", error.phaseVoltage.ToString() });
|
||||
|
||||
File.WriteAllLines(filePath, new[] { csvHeader, line });
|
||||
}
|
||||
}
|
||||
private void SetDefaultScreen()
|
||||
{
|
||||
string filePath = DataPathManager.GetDataFilePath("Screen.csv");
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
ScreeenTable screen = new ScreeenTable
|
||||
{
|
||||
Id = 1,
|
||||
brightness = 100,
|
||||
dimSec = 3300,
|
||||
offSec = 3600,
|
||||
port = "",
|
||||
boundRate = 19200,
|
||||
parity = 1,
|
||||
stopBits = 0,
|
||||
sendingTime = 50,
|
||||
warningLimit = 1,
|
||||
errorLimit = 2
|
||||
};
|
||||
|
||||
string csvHeader = "Id,Brightness,DimSec,OffSec,Port,BoundRate,Parity,StopBits,SendingTime,WarningLimit,ErrorLimit";
|
||||
string line = string.Join(",", new[] {
|
||||
screen.Id.ToString(),
|
||||
screen.brightness.ToString(),
|
||||
screen.dimSec.ToString(),
|
||||
screen.offSec.ToString(),
|
||||
screen.port,
|
||||
screen.boundRate.ToString(),
|
||||
screen.parity.ToString(),
|
||||
screen.stopBits.ToString(),
|
||||
screen.sendingTime.ToString(),
|
||||
screen.warningLimit.ToString(),
|
||||
screen.errorLimit.ToString()
|
||||
});
|
||||
|
||||
File.WriteAllLines(filePath, new[] { csvHeader, line });
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
535
DaireApplication/Views/UserController/ManualControl.axaml
Normal file
@@ -0,0 +1,535 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
Width="1280"
|
||||
Height="620"
|
||||
Background="#B3B3B3"
|
||||
x:Class="DaireApplication.ManualControl">
|
||||
<Grid RowDefinitions="*">
|
||||
<Grid Grid.Row="0" ColumnDefinitions="*,Auto,*">
|
||||
<Grid Grid.Column="0" RowDefinitions="2*,0.9*,2*" Margin="0,0,-100,0">
|
||||
<!--1st box-->
|
||||
<StackPanel Grid.Row="0" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<Border
|
||||
Width="290"
|
||||
Height="150"
|
||||
Background="#f9f9f9"
|
||||
CornerRadius="10"
|
||||
Padding="5,10">
|
||||
<StackPanel Spacing="5">
|
||||
<TextBlock
|
||||
FontSize="15"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="#ff0000"
|
||||
FontWeight="Medium">HELIX HEATING CONTROL</TextBlock>
|
||||
<!--Temp Control-->
|
||||
<StackPanel Orientation="Horizontal" Spacing="5">
|
||||
<Border
|
||||
Width="100"
|
||||
Height="63"
|
||||
Background="#e6e6e6"
|
||||
CornerRadius="5"
|
||||
Padding="5"
|
||||
Tag="t3"
|
||||
PointerPressed="ShowNumberKeyBoard">
|
||||
<StackPanel Spacing="7">
|
||||
<TextBlock
|
||||
FontSize="15"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="#666666">SET TEMP.</TextBlock>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<TextBlock
|
||||
x:Name="setHelixText"
|
||||
FontSize="23.5"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="#af196f">+0</TextBlock>
|
||||
<TextBlock
|
||||
FontSize="23.5"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="#af196f">°C</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<Border
|
||||
Width="100"
|
||||
Height="63"
|
||||
Background="#e6e6e6"
|
||||
CornerRadius="5"
|
||||
Padding="5">
|
||||
<StackPanel Spacing="7">
|
||||
<TextBlock
|
||||
FontSize="15"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="#666666">REAL TEMP.</TextBlock>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<TextBlock
|
||||
x:Name="pumbRealTemp"
|
||||
FontSize="23.5"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="#000000">
|
||||
0
|
||||
</TextBlock>
|
||||
<TextBlock
|
||||
FontSize="23.5"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="#000000">°C</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<StackPanel Spacing="3">
|
||||
<Border Width="70"
|
||||
Height="30"
|
||||
Background="#e6e6e6"
|
||||
CornerRadius="5"
|
||||
Padding="5">
|
||||
<StackPanel Spacing="9">
|
||||
<TextBlock FontSize="15"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="#231f20">AUTO</TextBlock>
|
||||
<!-- Underline -->
|
||||
<Rectangle Fill="#666666" Height="5" Width="60" Margin="0,-15,0,0"></Rectangle>
|
||||
</StackPanel>
|
||||
|
||||
</Border>
|
||||
<Border Width="70"
|
||||
Height="30"
|
||||
Background="#e6e6e6"
|
||||
CornerRadius="5"
|
||||
Padding="5">
|
||||
<StackPanel Spacing="9">
|
||||
<TextBlock FontSize="15"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="#231f20">ON/OFF</TextBlock>
|
||||
<!-- Underline -->
|
||||
<Rectangle Fill="#666666" Height="5" Width="60" Margin="0,-15,0,0"></Rectangle>
|
||||
</StackPanel>
|
||||
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
<Border Width="276"
|
||||
Height="40"
|
||||
Background="#e6e6e6"
|
||||
CornerRadius="5"
|
||||
Padding="5">
|
||||
<StackPanel Spacing="13">
|
||||
<TextBlock
|
||||
FontSize="19"
|
||||
Foreground="#231f20"
|
||||
HorizontalAlignment="Center">HELIX MOTOR ON / OFF</TextBlock>
|
||||
<!-- Underline -->
|
||||
<Rectangle Fill="#666666" Height="5" Width="265" Margin="0,-15,0,0"></Rectangle>
|
||||
</StackPanel>
|
||||
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
<!--2ed box-->
|
||||
<StackPanel Grid.Row="1" HorizontalAlignment="Right" >
|
||||
<Border
|
||||
Width="290"
|
||||
Height="55"
|
||||
Background="#f9f9f9"
|
||||
CornerRadius="10"
|
||||
Padding="5">
|
||||
<StackPanel>
|
||||
<TextBlock FontSize="15"
|
||||
Foreground="#800000"
|
||||
HorizontalAlignment="Center"
|
||||
FontWeight="Medium">TANK WALL TEMPERETURE</TextBlock>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<TextBlock
|
||||
x:Name="tankWallRealTemp"
|
||||
FontSize="23"
|
||||
FontWeight="DemiBold"
|
||||
Foreground="#333333"
|
||||
>0</TextBlock>
|
||||
<TextBlock FontSize="23"
|
||||
FontWeight="DemiBold"
|
||||
Foreground="#333333"
|
||||
>°C</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
</Border>
|
||||
</StackPanel>
|
||||
<!--3rd box-->
|
||||
<StackPanel Grid.Row="2" HorizontalAlignment="Right" >
|
||||
<Border
|
||||
Width="290"
|
||||
Height="150"
|
||||
Background="#f9f9f9"
|
||||
CornerRadius="10"
|
||||
Padding="5,10">
|
||||
<StackPanel Spacing="5">
|
||||
<TextBlock
|
||||
FontSize="15"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="#ff0000"
|
||||
FontWeight="Medium">TANK HEATING CONTROL</TextBlock>
|
||||
<!--Temp Control-->
|
||||
<StackPanel Orientation="Horizontal" Spacing="5">
|
||||
<Border
|
||||
Width="100"
|
||||
Height="63"
|
||||
Background="#e6e6e6"
|
||||
CornerRadius="5"
|
||||
Padding="5"
|
||||
Tag="t1"
|
||||
PointerPressed="ShowNumberKeyBoard">
|
||||
<StackPanel Spacing="7">
|
||||
<TextBlock
|
||||
FontSize="15"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="#666666">SET TEMP.</TextBlock>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<TextBlock
|
||||
|
||||
x:Name="setTankBtmText"
|
||||
FontSize="23.5"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="#af196f">+0</TextBlock>
|
||||
<TextBlock
|
||||
FontSize="23.5"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="#af196f">°C</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<Border
|
||||
Width="100"
|
||||
Height="63"
|
||||
Background="#e6e6e6"
|
||||
CornerRadius="5"
|
||||
Padding="5">
|
||||
<StackPanel Spacing="7">
|
||||
<TextBlock
|
||||
FontSize="15"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="#666666">REAL TEMP.</TextBlock>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<TextBlock
|
||||
x:Name="tankBtmRealTemp"
|
||||
FontSize="23.5"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="#000000">0</TextBlock>
|
||||
<TextBlock
|
||||
FontSize="23.5"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="#000000">°C</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<StackPanel Spacing="3">
|
||||
<Border Width="70"
|
||||
Height="30"
|
||||
Background="#e6e6e6"
|
||||
CornerRadius="5"
|
||||
Padding="5">
|
||||
<StackPanel Spacing="9">
|
||||
<TextBlock FontSize="15"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="#231f20">AUTO</TextBlock>
|
||||
<!-- Underline -->
|
||||
<Rectangle Fill="#666666" Height="5" Width="60" Margin="0,-15,0,0"></Rectangle>
|
||||
</StackPanel>
|
||||
|
||||
</Border>
|
||||
<Border Width="70"
|
||||
Height="30"
|
||||
Background="#e6e6e6"
|
||||
CornerRadius="5"
|
||||
Padding="5">
|
||||
<StackPanel Spacing="9">
|
||||
<TextBlock FontSize="15"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="#231f20">ON/OFF</TextBlock>
|
||||
<!-- Underline -->
|
||||
<Rectangle Fill="#666666" Height="5" Width="60" Margin="0,-15,0,0"></Rectangle>
|
||||
</StackPanel>
|
||||
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
<Border Width="276"
|
||||
Height="40"
|
||||
Background="#e6e6e6"
|
||||
CornerRadius="5"
|
||||
Padding="5">
|
||||
<StackPanel Spacing="13">
|
||||
<TextBlock
|
||||
FontSize="19"
|
||||
Foreground="#231f20"
|
||||
HorizontalAlignment="Center">HELIX MOTOR ON / OFF</TextBlock>
|
||||
<!-- Underline -->
|
||||
<Rectangle Fill="#666666" Height="5" Width="265" Margin="0,-15,0,0"></Rectangle>
|
||||
</StackPanel>
|
||||
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<Grid Grid.Column="1" Height="596" Width="484">
|
||||
|
||||
|
||||
<Grid.Background >
|
||||
<ImageBrush Source="/Assets/ManualControlMachine.png" />
|
||||
</Grid.Background>
|
||||
</Grid>
|
||||
<Grid Grid.Column="2" RowDefinitions="*,0*,*,*" HorizontalAlignment="Left">
|
||||
<Border Width="290"
|
||||
Height="103"
|
||||
Background="#f9f9f9"
|
||||
CornerRadius="10"
|
||||
HorizontalAlignment="Left"
|
||||
Margin="-140,0,0,0"
|
||||
Padding="5">
|
||||
<StackPanel>
|
||||
<TextBlock FontSize="15"
|
||||
Foreground="#0000ff"
|
||||
FontWeight="Medium"
|
||||
HorizontalAlignment="Center">CHOCOLATE COOLING CONTROL</TextBlock>
|
||||
<StackPanel Orientation="Horizontal" Spacing="5">
|
||||
<Border
|
||||
Width="100"
|
||||
Height="63"
|
||||
Background="#e6e6e6"
|
||||
CornerRadius="5"
|
||||
Padding="5"
|
||||
Tag="t4"
|
||||
PointerPressed="ShowNumberKeyBoard">
|
||||
<StackPanel Spacing="7">
|
||||
<TextBlock
|
||||
FontSize="15"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="#666666">SET TEMP.</TextBlock>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<TextBlock
|
||||
x:Name="setChocolateText"
|
||||
|
||||
FontSize="23.5"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="#af196f">+0</TextBlock>
|
||||
<TextBlock
|
||||
FontSize="23.5"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="#af196f">°C</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<Border
|
||||
Width="100"
|
||||
Height="63"
|
||||
Background="#e6e6e6"
|
||||
CornerRadius="5"
|
||||
Padding="5">
|
||||
<StackPanel Spacing="7">
|
||||
<TextBlock
|
||||
FontSize="15"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="#666666">REAL TEMP.</TextBlock>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<TextBlock
|
||||
x:Name="ChocolateRealTemp"
|
||||
|
||||
FontSize="23.5"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="#000000">0</TextBlock>
|
||||
<TextBlock
|
||||
FontSize="23.5"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="#000000">°C</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<StackPanel Spacing="3">
|
||||
<Border Width="70"
|
||||
Height="30"
|
||||
Background="#e6e6e6"
|
||||
CornerRadius="5"
|
||||
Padding="5">
|
||||
<StackPanel Spacing="9">
|
||||
<TextBlock FontSize="15"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="#231f20">AUTO</TextBlock>
|
||||
<!-- Underline -->
|
||||
<Rectangle Fill="#666666" Height="5" Width="60" Margin="0,-15,0,0"></Rectangle>
|
||||
</StackPanel>
|
||||
|
||||
</Border>
|
||||
<Border Width="70"
|
||||
Height="30"
|
||||
Background="#e6e6e6"
|
||||
CornerRadius="5"
|
||||
Padding="5">
|
||||
<StackPanel Spacing="9">
|
||||
<TextBlock FontSize="15"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="#231f20">ON/OFF</TextBlock>
|
||||
<!-- Underline -->
|
||||
<Rectangle Fill="#666666" Height="5" Width="60" Margin="0,-15,0,0"></Rectangle>
|
||||
</StackPanel>
|
||||
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
</Border>
|
||||
<Border Width="150"
|
||||
Height="90"
|
||||
Background="#f9f9f9"
|
||||
Grid.Row="1" CornerRadius="10"
|
||||
Padding="5"
|
||||
PointerPressed="ToggleMoldHeaterClick"
|
||||
>
|
||||
<StackPanel>
|
||||
<TextBlock FontSize="15"
|
||||
Foreground="#666666"
|
||||
HorizontalAlignment="Center">MOLD HEATER</TextBlock>
|
||||
<TextBlock x:Name="MoldHeaterStatus" FontSize="47"
|
||||
Foreground="#231f20"
|
||||
HorizontalAlignment="Center">OFF</TextBlock>
|
||||
<!-- Underline -->
|
||||
<Rectangle x:Name="MoldHeaterUnderline" Fill="#666666" Height="5" Width="110" Margin="0,-10,0,0"></Rectangle>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<Border Width="150"
|
||||
Height="90"
|
||||
Background="#f9f9f9"
|
||||
Grid.Row="2" CornerRadius="10"
|
||||
Padding="5"
|
||||
PointerPressed="ToggleVibrationClick"
|
||||
>
|
||||
<StackPanel>
|
||||
<TextBlock FontSize="15"
|
||||
Foreground="#666666"
|
||||
HorizontalAlignment="Center">VIBRATION</TextBlock>
|
||||
<TextBlock x:Name="VibrationStatus" FontSize="47"
|
||||
Foreground="#231f20"
|
||||
HorizontalAlignment="Center">OFF</TextBlock>
|
||||
<!-- Underline -->
|
||||
<Rectangle x:Name="VibrationUnderline" Fill="#666666" Height="5" Width="110" Margin="0,-10,0,0"></Rectangle>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<Border Width="150"
|
||||
Height="90"
|
||||
Background="#f9f9f9"
|
||||
Grid.Row="3" CornerRadius="10"
|
||||
VerticalAlignment="Top"
|
||||
Margin="0,-20,0,0"
|
||||
Padding="5"
|
||||
PointerPressed="ToggleVibHeaterClick"
|
||||
>
|
||||
<StackPanel>
|
||||
<TextBlock FontSize="15"
|
||||
Foreground="#666666"
|
||||
HorizontalAlignment="Center">VIB. HEATER</TextBlock>
|
||||
<TextBlock x:Name="VibHeaterStatus" FontSize="47"
|
||||
Foreground="#231f20"
|
||||
HorizontalAlignment="Center">OFF</TextBlock>
|
||||
<!-- Underline -->
|
||||
<Rectangle x:Name="VibHeaterUnderline" Fill="#666666" Height="5" Width="110" Margin="0,-10,0,0"></Rectangle>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
|
||||
|
||||
</Grid>
|
||||
<!--number keyBoard-->
|
||||
<Border x:Name="keyBoardPopup"
|
||||
Background="#80000000"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
IsVisible="False"
|
||||
ZIndex="50"
|
||||
PointerPressed="OnPopupOverlayPointerPressed">
|
||||
<Grid MaxWidth="500" MaxHeight="500" HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
Margin="0,0,0,0"
|
||||
PointerPressed="InnerPopupPointerPressed">
|
||||
<Border x:Name="PopupControl"
|
||||
BorderThickness="2"
|
||||
CornerRadius="10"
|
||||
Padding="10"
|
||||
PointerPressed="InnerPopupPointerPressed">
|
||||
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Spacing="10">
|
||||
<!-- Popup Content (Keypad etc.) -->
|
||||
<Grid IsVisible="True">
|
||||
<Grid.Styles>
|
||||
<Style Selector="Button">
|
||||
<Setter Property="Background" Value="White"/>
|
||||
<Setter Property="CornerRadius" Value="20"/>
|
||||
<Setter Property="Width" Value="100"/>
|
||||
<Setter Property="Height" Value="100"/>
|
||||
<Setter Property="FontSize" Value="50"/>
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Center"/>
|
||||
</Style>
|
||||
<Style Selector="Button:pointerover /template/ContentPresenter">
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
<Setter Property="Background" Value="White"/>
|
||||
<Setter Property="CornerRadius" Value="20"/>
|
||||
<Setter Property="RenderTransform" Value="scale(1.11)"/>
|
||||
</Style>
|
||||
</Grid.Styles>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.Row="1" Margin="10">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="1*"/>
|
||||
<RowDefinition Height="1*"/>
|
||||
<RowDefinition Height="1*"/>
|
||||
<RowDefinition Height="1*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<!-- Keypad Buttons -->
|
||||
<Button Content="1" Grid.Row="0" Grid.Column="0" FontSize="24" Background="White" Margin="5" Click="OnKeyClick"/>
|
||||
<Button Content="2" Grid.Row="0" Grid.Column="1" FontSize="24" Background="White" Margin="5" Click="OnKeyClick"/>
|
||||
<Button Content="3" Grid.Row="0" Grid.Column="2" FontSize="24" Background="White" Margin="5" Click="OnKeyClick"/>
|
||||
<Button Content="4" Grid.Row="1" Grid.Column="0" FontSize="24" Background="White" Margin="5" Click="OnKeyClick"/>
|
||||
<Button Content="5" Grid.Row="1" Grid.Column="1" FontSize="24" Background="White" Margin="5" Click="OnKeyClick"/>
|
||||
<Button Content="6" Grid.Row="1" Grid.Column="2" FontSize="24" Background="White" Margin="5" Click="OnKeyClick"/>
|
||||
<Button Content="7" Grid.Row="2" Grid.Column="0" FontSize="24" Background="White" Margin="5" Click="OnKeyClick"/>
|
||||
<Button Content="8" Grid.Row="2" Grid.Column="1" FontSize="24" Background="White" Margin="5" Click="OnKeyClick"/>
|
||||
<Button Content="9" Grid.Row="2" Grid.Column="2" FontSize="24" Background="White" Margin="5" Click="OnKeyClick"/>
|
||||
<Button Content="BACK" Grid.Row="3" Grid.Column="0" FontSize="20" Background="#D3D3D3" Margin="5" Click="OnBackClick"/>
|
||||
<Button Content="0" Grid.Row="3" Grid.Column="1" FontSize="24" Background="White" Margin="5" Click="OnKeyClick"/>
|
||||
<Button x:Name="enterBtn" Content="ENTER" Grid.Row="3" Grid.Column="2" FontSize="20" Background="#A4275D" Foreground="White" Margin="5" Click="EnterClick"/>
|
||||
<Button Content="-" Grid.Row="3" Grid.Column="3" FontSize="50" Background="White" Foreground="Black"
|
||||
Margin="5" Click="OnKeyClick"/>
|
||||
<Button Content="+" Grid.Row="2" Grid.Column="3" FontSize="50" Background="White" Foreground="Black"
|
||||
Margin="5" Click="OnKeyClick"/>
|
||||
<Button Content="." Grid.Row="1" Grid.Column="3" FontSize="50" Background="White" Foreground="Black"
|
||||
Margin="5" Click="OnKeyClick"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
</Grid>
|
||||
|
||||
|
||||
|
||||
|
||||
</UserControl>
|
||||
266
DaireApplication/Views/UserController/ManualControl.axaml.cs
Normal file
@@ -0,0 +1,266 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.LogicalTree;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.Media;
|
||||
using DaireApplication.DataBase;
|
||||
using DaireApplication.ViewModels;
|
||||
using DaireApplication.Views;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection.PortableExecutable;
|
||||
|
||||
namespace DaireApplication;
|
||||
|
||||
public partial class ManualControl : UserControl
|
||||
{
|
||||
private MainWindow? _mainWindow;
|
||||
bool isNegative = false;
|
||||
TextBlock targetText = new TextBlock();
|
||||
float oldValue = 0;
|
||||
public MachineTable _machine { get; set; }
|
||||
|
||||
|
||||
public ManualControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
public ManualControl(MainWindow mainWindow)
|
||||
{
|
||||
_mainWindow = mainWindow;
|
||||
_machine = new MachineTable();
|
||||
|
||||
InitializeComponent();
|
||||
setDefaultSettings();
|
||||
getUiElementes();
|
||||
}
|
||||
private void setDefaultSettings()
|
||||
{
|
||||
_mainWindow.minimizeBtn.IsVisible = false;
|
||||
//Set Track Up
|
||||
_mainWindow.HomeTrack.IsVisible = true;
|
||||
//_mainWindow.HomePolygon.Stroke = Avalonia.Media.Brushes.Black;
|
||||
_mainWindow.RecipeSelTrack.IsVisible = false;
|
||||
_mainWindow.RunInterfaceTrack.IsVisible = false;
|
||||
_mainWindow.RecipePanelTrack.IsVisible = true;
|
||||
_mainWindow.RecipePanelPolygon.Stroke = Avalonia.Media.Brushes.Black;
|
||||
_mainWindow.RecipeEditTrack.IsVisible = false;
|
||||
_mainWindow.DiagnosticsTrack.IsVisible = false;
|
||||
_mainWindow.AdvanceSettingsTrack.IsVisible = false;
|
||||
_mainWindow.SoftwareTrack.IsVisible = false;
|
||||
_mainWindow.SettingTrack.IsVisible = false;
|
||||
_mainWindow.TitleBtn.IsVisible = false;
|
||||
_mainWindow.ManualControlTrack.IsVisible = true;
|
||||
_mainWindow.ManualControlPolygon.Stroke = Brush.Parse("#A4275D");
|
||||
//_mainWindow.Title.Text = _recipeTable.Name;
|
||||
|
||||
//Set Footer
|
||||
_mainWindow.footerMsg.IsVisible = false;
|
||||
_mainWindow.footer.Background = Avalonia.Media.Brushes.WhiteSmoke;
|
||||
_mainWindow.footerDate.Text = DateTime.Now.ToString("dd/MM/yyyy");
|
||||
_mainWindow.footerTime.Text = DateTime.Now.ToString("hh:mm tt");
|
||||
_mainWindow.footerDateContainer.IsVisible = true;
|
||||
_mainWindow.footerStartBtn.IsVisible = false;
|
||||
_mainWindow.adminBtns.IsVisible = true;
|
||||
_mainWindow.version.IsVisible = false;
|
||||
_mainWindow.chefBtns.IsVisible = false;
|
||||
}
|
||||
|
||||
private void ToggleMoldHeaterClick(object? sender, PointerPressedEventArgs e)
|
||||
{
|
||||
if (MoldHeaterStatus.Text == "ON")
|
||||
{
|
||||
_mainWindow.moldHeaterMotor = 0;
|
||||
//MoldHeaterStatus.Text = "OFF";
|
||||
//MoldHeaterUnderline.Fill = Brush.Parse("#666666");
|
||||
}
|
||||
else
|
||||
{
|
||||
_mainWindow.moldHeaterMotor = 1;
|
||||
//MoldHeaterStatus.Text = "ON";
|
||||
//MoldHeaterUnderline.Fill = Brush.Parse("#A4275D");
|
||||
}
|
||||
}
|
||||
|
||||
private void ToggleVibrationClick(object? sender, PointerPressedEventArgs e)
|
||||
{
|
||||
if (VibrationStatus.Text == "ON")
|
||||
{
|
||||
_mainWindow.vibrationMotor = 0;
|
||||
//VibrationStatus.Text = "OFF";
|
||||
//VibrationUnderline.Fill = Brush.Parse("#666666");
|
||||
}
|
||||
else
|
||||
{
|
||||
_mainWindow.vibrationMotor = 1;
|
||||
//VibrationStatus.Text = "ON";
|
||||
//VibrationUnderline.Fill = Brush.Parse("#A4275D");
|
||||
}
|
||||
}
|
||||
|
||||
private void ToggleVibHeaterClick(object? sender, PointerPressedEventArgs e)
|
||||
{
|
||||
if (VibHeaterStatus.Text == "ON")
|
||||
{
|
||||
_mainWindow.vibHeaterMotor = 0;
|
||||
//VibHeaterStatus.Text = "OFF";
|
||||
//VibHeaterUnderline.Fill = Brush.Parse("#666666");
|
||||
}
|
||||
else
|
||||
{
|
||||
_mainWindow.vibHeaterMotor = 1;
|
||||
//VibHeaterStatus.Text = "ON";
|
||||
//VibHeaterUnderline.Fill = Brush.Parse("#A4275D");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPopupOverlayPointerPressed(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
if (isNegative)
|
||||
{
|
||||
targetText.Text = "-" + oldValue.ToString("0.0");
|
||||
}
|
||||
else
|
||||
{
|
||||
targetText.Text = "+" + oldValue.ToString("0.0");
|
||||
}
|
||||
keyBoardPopup.IsVisible = false;
|
||||
}
|
||||
private void InnerPopupPointerPressed(object? sender, PointerPressedEventArgs e)
|
||||
{
|
||||
e.Handled = true;
|
||||
}
|
||||
private void OnKeyClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Button button)
|
||||
{
|
||||
if ((button.Content == "+" || button.Content == "-") && targetText.Text.Length > 0)
|
||||
{
|
||||
|
||||
}
|
||||
else if ((targetText.Text.Length == 0 && button.Content == ".") || (targetText.Text.Contains(".") && button.Content == "."))
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
targetText.Text += button.Content;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
private void OnBackClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(targetText.Text))
|
||||
{
|
||||
// Remove the last character from the text box
|
||||
targetText.Text = targetText.Text.Remove(targetText.Text.Length - 1, 1);
|
||||
//number = number.Remove(number.Length - 1);
|
||||
}
|
||||
|
||||
}
|
||||
private async void EnterClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var tankBtm = _mainWindow._mapping.Find(x => x.Name.ToLower() == "Tank Bottom Temp".ToLower());
|
||||
var pumb = _mainWindow._mapping.Find(x => x.Name.ToLower() == "Pump Temp".ToLower());
|
||||
var fount = _mainWindow._mapping.Find(x => x.Name.ToLower() == "Fountain Temp".ToLower());
|
||||
List<int> setTempValues = new List<int>();
|
||||
setTempValues.AddRange([_mainWindow.holdingRegister.setTemp1, _mainWindow.holdingRegister.setTemp2, _mainWindow.holdingRegister.setTemp3, _mainWindow.holdingRegister.setTemp4]);
|
||||
|
||||
if (sender is Button button)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(targetText.Text))
|
||||
{
|
||||
float number = float.Parse(targetText.Text);
|
||||
|
||||
if (char.IsDigit(targetText.Text[0]))
|
||||
{
|
||||
targetText.Text = "+" + number.ToString("0.0");
|
||||
}
|
||||
else
|
||||
{
|
||||
targetText.Text = number.ToString("0.0");
|
||||
}
|
||||
|
||||
var machine = _machine.ReadMachine();
|
||||
if (button.Tag.ToString() == "t1")
|
||||
{
|
||||
foreach (var item in tankBtm.BitNumbers)
|
||||
{
|
||||
setTempValues[item - 8] = (int)(number * 10);
|
||||
}
|
||||
machine.setTemp1 = number;
|
||||
}
|
||||
else if (button.Tag.ToString() == "t3")
|
||||
{
|
||||
foreach (var item in pumb.BitNumbers)
|
||||
{
|
||||
setTempValues[item - 8] = (int)(number * 10);
|
||||
}
|
||||
machine.setTemp3 = number;
|
||||
}
|
||||
else if (button.Tag.ToString() == "t4")
|
||||
{
|
||||
foreach (var item in fount.BitNumbers)
|
||||
{
|
||||
setTempValues[item - 8] = (int)(number * 10);
|
||||
}
|
||||
machine.setTemp4 = number;
|
||||
}
|
||||
_mainWindow.holdingRegister.setTemp1 = setTempValues[0];
|
||||
_mainWindow.holdingRegister.setTemp2 = setTempValues[1];
|
||||
_mainWindow.holdingRegister.setTemp3 = setTempValues[2];
|
||||
_mainWindow.holdingRegister.setTemp4 = setTempValues[3];
|
||||
_machine.UpdateMachine(machine);
|
||||
getUiElementes();
|
||||
|
||||
|
||||
keyBoardPopup.IsVisible = false;
|
||||
await _mainWindow.WriteToSerialAsync("DiagnosticsEnter");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowNumberKeyBoard(object? sender, PointerPressedEventArgs e)
|
||||
{
|
||||
if (sender is Border border)
|
||||
{
|
||||
//var parent = border.Parent as StackPanel;
|
||||
//var brother = parent.Children[0] as Border;
|
||||
//targetButton = brother.Child as Button;
|
||||
if (border.Tag?.ToString() == "t1")
|
||||
{
|
||||
targetText = setTankBtmText;
|
||||
}
|
||||
else if (border.Tag?.ToString() == "t3")
|
||||
{
|
||||
targetText = setHelixText;
|
||||
}
|
||||
else if (border.Tag?.ToString() == "t4")
|
||||
{
|
||||
targetText = setChocolateText;
|
||||
}
|
||||
enterBtn.Tag = border.Tag;
|
||||
|
||||
isNegative = targetText.Text.StartsWith("-");
|
||||
var x = targetText.Text.Substring(1);
|
||||
|
||||
oldValue = float.Parse(x);
|
||||
targetText.Text = "";
|
||||
keyBoardPopup.IsVisible = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void getUiElementes()
|
||||
{
|
||||
var machine = _machine.ReadMachine();
|
||||
setTankBtmText.Text = char.IsDigit(machine.setTemp1.ToString()[0]) ? "+" + machine.setTemp1.ToString() : machine.setTemp1.ToString("0.0");
|
||||
setHelixText.Text = char.IsDigit(machine.setTemp3.ToString()[0]) ? "+" + machine.setTemp3.ToString() : machine.setTemp3.ToString("0.0");
|
||||
setChocolateText.Text = char.IsDigit(machine.setTemp4.ToString()[0]) ? "+" + machine.setTemp4.ToString() : machine.setTemp4.ToString("0.0");
|
||||
}
|
||||
}
|
||||
341
DaireApplication/Views/UserController/Recipe.axaml
Normal file
@@ -0,0 +1,341 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
Width="1200"
|
||||
x:Class="DaireApplication.Recipe">
|
||||
<Grid RowDefinitions="*">
|
||||
<!-- Main Area-->
|
||||
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,1.5*" >
|
||||
<Grid Grid.Column="1" >
|
||||
<Grid x:Name="machinePic" Height="698" Width="465" >
|
||||
<Grid.Background >
|
||||
<ImageBrush Source="/Assets/Machine.png" Stretch="UniformToFill"/>
|
||||
</Grid.Background>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
<Grid Grid.Column="0" RowDefinitions="Auto,*">
|
||||
<StackPanel Margin="10,50,0,10" Grid.Row="0" HorizontalAlignment="Center" >
|
||||
<Label Foreground="#333333" FontSize="40" FontWeight="Normal" x:Name="RecipeTitle">Recipe SELECTION</Label>
|
||||
</StackPanel>
|
||||
<ScrollViewer Grid.Row="1" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" Margin="0,0">
|
||||
<Grid x:Name="DynamicGrid">
|
||||
<!-- Define three columns -->
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid.Styles>
|
||||
|
||||
|
||||
<Style Selector="Button">
|
||||
<Setter Property="Background" Value="White"></Setter>
|
||||
</Style>
|
||||
|
||||
<Style Selector="Button:pointerover /template/ContentPresenter">
|
||||
<Setter Property="RenderTransform" Value="scale(1.11)"></Setter>
|
||||
<Setter Property="Background" Value="White"></Setter>
|
||||
|
||||
|
||||
</Style>
|
||||
|
||||
|
||||
</Grid.Styles>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Dynamic rows will be generated programmatically in code-behind -->
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
|
||||
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Overlay Background for Add Popup -->
|
||||
<Border x:Name="PopupOverlay" Background="#80000000" Grid.RowSpan="3" IsVisible="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ZIndex="99" PointerPressed="OnPopupOverlayPointerPressed">
|
||||
<!-- Popup User Control -->
|
||||
|
||||
<!-- Module for Name Entry -->
|
||||
<Grid x:Name="NameModule" PointerPressed="" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="20" IsVisible="True">
|
||||
<Border Background="White" CornerRadius="10" Padding="20" BorderThickness="1" ZIndex="101" BorderBrush="#CCC">
|
||||
<StackPanel Spacing="15">
|
||||
<!-- Label for Text Input -->
|
||||
<!-- Label -->
|
||||
|
||||
<TextBlock x:Name="foucs" Text="Enter Recipe Name:"
|
||||
FontSize="18"
|
||||
FontWeight="Bold"
|
||||
Foreground="#333"
|
||||
Margin="0,0,0,8" />
|
||||
|
||||
<Border x:Name="nameBorder">
|
||||
<TextBox x:Name="NameInput"
|
||||
Width="300"
|
||||
Height="30"
|
||||
BorderBrush="#CCC"
|
||||
BorderThickness="1"
|
||||
MaxLength="9"
|
||||
></TextBox>
|
||||
</Border>
|
||||
|
||||
<!-- Local styles for this specific TextBox -->
|
||||
|
||||
<!-- Button Panel -->
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Spacing="10">
|
||||
<!-- Save Button -->
|
||||
<Button x:Name="SaveButton"
|
||||
Content="Save"
|
||||
FontSize="16"
|
||||
Padding="10,5"
|
||||
Click="saveRecipeClick"
|
||||
Foreground="White" >
|
||||
<Button.Background>
|
||||
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
|
||||
<GradientStop Color="#A4275D" Offset="0" />
|
||||
<GradientStop Color="#A4275D" Offset="1" />
|
||||
</LinearGradientBrush>
|
||||
</Button.Background>
|
||||
<Button.Effect>
|
||||
|
||||
</Button.Effect>
|
||||
</Button>
|
||||
<!-- Cancel Button -->
|
||||
<Button x:Name="CancelButton"
|
||||
Content="Cancel"
|
||||
FontSize="16"
|
||||
Padding="10,5"
|
||||
Background="Gray"
|
||||
Foreground="White"
|
||||
Click="OnPopupOverlayPointerPressed">
|
||||
<Button.Effect>
|
||||
|
||||
</Button.Effect>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- Overlay Background for Delet Popup -->
|
||||
<Border x:Name="managePopupOverlay" Background="#80000000" Grid.RowSpan="3" IsVisible="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ZIndex="99" PointerPressed="OnDeletePopupOverlayPointerPressed">
|
||||
<!-- Popup User Control -->
|
||||
|
||||
<!-- Module for Name Entry -->
|
||||
<Grid PointerPressed="" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="20" IsVisible="True">
|
||||
<Border Background="White" CornerRadius="10" Padding="20" BorderThickness="1" ZIndex="101" BorderBrush="#CCC">
|
||||
<StackPanel Spacing="15">
|
||||
<!-- Label for Text Input -->
|
||||
<!-- Label -->
|
||||
|
||||
|
||||
<TextBlock Text="modify the action "
|
||||
FontSize="20"
|
||||
FontWeight="Bold"
|
||||
Foreground="Red"
|
||||
Margin="0,0,0,8"
|
||||
HorizontalAlignment="Center"/>
|
||||
|
||||
<!-- Button Panel -->
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Spacing="10">
|
||||
<!-- update Button -->
|
||||
<Button
|
||||
Name="updateActionBtn"
|
||||
Content="Update"
|
||||
FontSize="16"
|
||||
Padding="10,5"
|
||||
Click="UpdateActionClick"
|
||||
Foreground="White" >
|
||||
<Button.Background>
|
||||
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
|
||||
<GradientStop Color="#A4275D" Offset="0" />
|
||||
<GradientStop Color="#A4275D" Offset="1" />
|
||||
</LinearGradientBrush>
|
||||
</Button.Background>
|
||||
</Button>
|
||||
<!-- delete Button -->
|
||||
<Button
|
||||
Name="deleteActionBtn"
|
||||
Content="Delete"
|
||||
FontSize="16"
|
||||
Padding="10,5"
|
||||
Click="deleteActionClick"
|
||||
Foreground="White"
|
||||
Background="Red">
|
||||
</Button>
|
||||
<!-- No Button -->
|
||||
<Button
|
||||
Content="Cancel"
|
||||
FontSize="16"
|
||||
Padding="10,5"
|
||||
Background="Gray"
|
||||
Foreground="White"
|
||||
Click="OnDeletePopupOverlayPointerPressed">
|
||||
<Button.Effect>
|
||||
|
||||
</Button.Effect>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
<!-- Overlay Background for Add Popup -->
|
||||
<Border x:Name="updatePopupOverlay" Background="#80000000" Grid.RowSpan="3" IsVisible="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ZIndex="99" PointerPressed="OnDeletePopupOverlayPointerPressed">
|
||||
<!-- Popup User Control -->
|
||||
|
||||
<!-- Module for Name Entry -->
|
||||
<Grid PointerPressed="" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="20" IsVisible="True">
|
||||
<Border Background="White" CornerRadius="10" Padding="20" BorderThickness="1" ZIndex="101" BorderBrush="#CCC">
|
||||
<StackPanel Spacing="15">
|
||||
<!-- Label for Text Input -->
|
||||
<!-- Label -->
|
||||
|
||||
<TextBlock Text="Rename:"
|
||||
FontSize="18"
|
||||
FontWeight="Bold"
|
||||
Foreground="#333"
|
||||
Margin="0,0,0,8" />
|
||||
|
||||
<Border x:Name="updateBorder">
|
||||
<TextBox x:Name="updateInput"
|
||||
Width="300"
|
||||
Height="30"
|
||||
BorderBrush="#CCC"
|
||||
BorderThickness="1"
|
||||
|
||||
MaxLength="9"
|
||||
>
|
||||
<!-- Local styles for this specific TextBox -->
|
||||
<TextBox.Styles>
|
||||
<!-- Normal (unfocused) style -->
|
||||
<Style Selector="TextBox">
|
||||
<Setter Property="Background" Value="White" />
|
||||
<Setter Property="Foreground" Value="Black" />
|
||||
</Style>
|
||||
|
||||
|
||||
</TextBox.Styles>
|
||||
</TextBox>
|
||||
</Border>
|
||||
|
||||
|
||||
<!-- Button Panel -->
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Spacing="10">
|
||||
<!-- Save Button -->
|
||||
<Button x:Name="saveUpdateBtn"
|
||||
Content="Save"
|
||||
FontSize="16"
|
||||
Padding="10,5"
|
||||
Click="SaveUpdateClick"
|
||||
Foreground="White" >
|
||||
<Button.Background>
|
||||
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
|
||||
<GradientStop Color="#A4275D" Offset="0" />
|
||||
<GradientStop Color="#A4275D" Offset="1" />
|
||||
</LinearGradientBrush>
|
||||
</Button.Background>
|
||||
</Button>
|
||||
<!-- Cancel Button -->
|
||||
<Button x:Name="cancelBtn"
|
||||
Content="Cancel"
|
||||
FontSize="16"
|
||||
Padding="10,5"
|
||||
Background="Gray"
|
||||
Foreground="White"
|
||||
Click="OnDeletePopupOverlayPointerPressed">
|
||||
<Button.Effect>
|
||||
|
||||
</Button.Effect>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- Overlay Background for Delet Popup -->
|
||||
<Border x:Name="DeletePopupOverlay" Background="#80000000" Grid.RowSpan="3" IsVisible="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ZIndex="99" PointerPressed="OnDeletePopupOverlayPointerPressed">
|
||||
<!-- Popup User Control -->
|
||||
|
||||
<!-- Module for Name Entry -->
|
||||
<Grid PointerPressed="" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="20" IsVisible="True">
|
||||
<Border Background="White" CornerRadius="10" Padding="20" BorderThickness="1" ZIndex="101" BorderBrush="#CCC">
|
||||
<StackPanel Spacing="15">
|
||||
<!-- Label for Text Input -->
|
||||
<!-- Label -->
|
||||
|
||||
|
||||
<TextBlock Text="Delete Warning!!"
|
||||
FontSize="20"
|
||||
FontWeight="Bold"
|
||||
Foreground="Red"
|
||||
Margin="0,0,0,8" />
|
||||
<StackPanel>
|
||||
<TextBlock x:Name="deleteMsg" Text="Are you sure?"
|
||||
FontSize="16"
|
||||
FontWeight="Bold"
|
||||
Foreground="#333"
|
||||
Margin="0,0,0,8" />
|
||||
</StackPanel>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Button Panel -->
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Spacing="10">
|
||||
<!-- yes Button -->
|
||||
<Button
|
||||
Content="Yes"
|
||||
FontSize="16"
|
||||
Padding="10,5"
|
||||
Click="YesBtnClick"
|
||||
Foreground="White" >
|
||||
<Button.Background>
|
||||
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
|
||||
<GradientStop Color="#A4275D" Offset="0" />
|
||||
<GradientStop Color="#A4275D" Offset="1" />
|
||||
</LinearGradientBrush>
|
||||
</Button.Background>
|
||||
<Button.Effect>
|
||||
|
||||
</Button.Effect>
|
||||
</Button>
|
||||
<!-- No Button -->
|
||||
<Button
|
||||
Content="No"
|
||||
FontSize="16"
|
||||
Padding="10,5"
|
||||
Background="Gray"
|
||||
Foreground="White"
|
||||
Click="OnDeletePopupOverlayPointerPressed">
|
||||
<Button.Effect>
|
||||
|
||||
</Button.Effect>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</Grid>
|
||||
|
||||
</UserControl>
|
||||
719
DaireApplication/Views/UserController/Recipe.axaml.cs
Normal file
@@ -0,0 +1,719 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Threading;
|
||||
using AvaloniaApplication1.DataBase;
|
||||
using DaireApplication.Views;
|
||||
using ReactiveUI;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DaireApplication;
|
||||
|
||||
public partial class Recipe : UserControl
|
||||
{
|
||||
Button recipeButton = new Button();
|
||||
private bool _isLongPress;
|
||||
|
||||
private MainWindow? _mainWindow;
|
||||
private UserTable? _currentUser;
|
||||
private RecipeTable _recipeTable=new RecipeTable();
|
||||
private Process? _keyboardProcess;
|
||||
|
||||
public Recipe()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
}
|
||||
public Recipe(MainWindow mainWindow,UserTable currentUser)
|
||||
{
|
||||
_currentUser = currentUser;
|
||||
_mainWindow = mainWindow;
|
||||
InitializeComponent();
|
||||
nameBorder.AddHandler(InputElement.PointerPressedEvent, OnTextBoxFocused, RoutingStrategies.Tunnel, handledEventsToo: true);
|
||||
updateBorder.AddHandler(InputElement.PointerPressedEvent, OnTextBoxFocused, RoutingStrategies.Tunnel, handledEventsToo: true);
|
||||
setDefaultSettings();
|
||||
addDynamicButtons();
|
||||
}
|
||||
|
||||
|
||||
private async void OnRecipeClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_isLongPress)
|
||||
{
|
||||
// Reset the flag for future interactions.
|
||||
_isLongPress = false;
|
||||
// Ignore this click since a long press was detected.
|
||||
return;
|
||||
}
|
||||
|
||||
if (sender is Button button)
|
||||
{
|
||||
if (_currentUser.CanEdit)
|
||||
{
|
||||
_mainWindow.FindControl<ContentControl>("ContentArea").Content = new RecipeEdit(_mainWindow, _currentUser, _recipeTable.ReadRecipesById(button.Name));
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
_mainWindow.FindControl<ContentControl>("ContentArea").Content = new Settings(_mainWindow, _currentUser, _recipeTable.ReadRecipesById(button.Name));
|
||||
_mainWindow.restBoard = true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
private async void deleteActionClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Button button)
|
||||
{
|
||||
deleteMsg.Text = $"You are about to delete {button.Tag}";
|
||||
DeletePopupOverlay.IsVisible = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
private async void UpdateActionClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Button button)
|
||||
{
|
||||
var text = recipeButton.Content as TextBlock;
|
||||
updateInput.Text = $"{text.Text}";
|
||||
updatePopupOverlay.IsVisible = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
private void OnLongRecipeClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (e is HoldingRoutedEventArgs args)
|
||||
{
|
||||
if (args.HoldingState == HoldingState.Started)
|
||||
{
|
||||
_isLongPress = true;
|
||||
|
||||
if (sender is Button button)
|
||||
{
|
||||
var targetText= button.Content as TextBlock;
|
||||
deleteActionBtn.Tag = targetText.Text;
|
||||
managePopupOverlay.IsVisible = true;
|
||||
recipeButton = button;
|
||||
|
||||
//recipeButton = button;
|
||||
//if (button.Content is TextBlock targetText)
|
||||
//{
|
||||
// deleteMsg.Text = $"You are about to delete {targetText.Text}";
|
||||
//}
|
||||
}
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
else if (args.HoldingState == HoldingState.Completed)
|
||||
{
|
||||
_isLongPress = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
private void CloseKeyboard()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_keyboardProcess != null)
|
||||
{
|
||||
// Kill the keyboard process
|
||||
_keyboardProcess.Kill();
|
||||
_keyboardProcess.Dispose();
|
||||
_keyboardProcess = null;
|
||||
|
||||
// Force kill any remaining keyboard processes
|
||||
var processKill = new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = "killall",
|
||||
Arguments = "-9 onboard matchbox-keyboard florence", // Common Linux on-screen keyboards
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true
|
||||
}
|
||||
};
|
||||
processKill.Start();
|
||||
processKill.WaitForExit(1000);
|
||||
processKill.Dispose();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error closing keyboard: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public void AttachHandlers(Button button)
|
||||
{
|
||||
if (button != null)
|
||||
{
|
||||
button.Holding += OnLongRecipeClick;
|
||||
|
||||
button.PointerPressed += (sender, e) =>
|
||||
{
|
||||
// Simulate a long press on any pointer (mouse or touch)
|
||||
var point = e.GetPosition(button);
|
||||
OnLongRecipeClick(sender, new HoldingRoutedEventArgs(HoldingState.Started, point, e.Pointer.Type));
|
||||
};
|
||||
|
||||
button.PointerReleased += (sender, e) =>
|
||||
{
|
||||
// End simulated long press
|
||||
var point = e.GetPosition(button);
|
||||
OnLongRecipeClick(sender, new HoldingRoutedEventArgs(HoldingState.Completed, point, e.Pointer.Type));
|
||||
};
|
||||
}
|
||||
}
|
||||
private async void OnAddRecipeClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Button button)
|
||||
{
|
||||
PopupOverlay.IsVisible = true;
|
||||
}
|
||||
|
||||
}
|
||||
private async void OnPopupOverlayPointerPressed(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
PopupOverlay.IsVisible = false;
|
||||
|
||||
|
||||
|
||||
}
|
||||
private async void OnDeletePopupOverlayPointerPressed(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
DeletePopupOverlay.IsVisible = false;
|
||||
managePopupOverlay.IsVisible = false;
|
||||
updatePopupOverlay.IsVisible = false;
|
||||
|
||||
}
|
||||
private async void YesBtnClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var result = _recipeTable.DeleteRecipe(recipeButton.Name);
|
||||
if (result)
|
||||
{
|
||||
addDynamicButtons();
|
||||
DeletePopupOverlay.IsVisible= false;
|
||||
managePopupOverlay.IsVisible = false;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
private async void SaveUpdateClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!_recipeTable.DoesNameExist(updateInput.Text))
|
||||
{
|
||||
var recipe = _recipeTable.ReadRecipesById(recipeButton.Name);
|
||||
recipe.Name = updateInput.Text;
|
||||
var result = _recipeTable.UpdateRecipe(recipe);
|
||||
if (result)
|
||||
{
|
||||
addDynamicButtons();
|
||||
managePopupOverlay.IsVisible = false;
|
||||
updatePopupOverlay.IsVisible = false;
|
||||
CloseKeyboard();
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CloseKeyboard();
|
||||
await MainWindow.MessageBox.Show(_mainWindow, "this name is already in use", "Error");
|
||||
_mainWindow.Topmost = false;
|
||||
_mainWindow.Focus();
|
||||
_mainWindow.Activate();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
private void showPopUp(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Button button)
|
||||
{
|
||||
recipeButton = button;
|
||||
button.Foreground = Brush.Parse("#A4275D");
|
||||
PopupOverlay.IsVisible = true;
|
||||
// Append the button's content to the input box
|
||||
//InputTextBox.Text += button.Content?.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
private async void saveRecipeClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Button button)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(NameInput.Text))
|
||||
{
|
||||
if (!_recipeTable.DoesNameExist(NameInput.Text))
|
||||
{
|
||||
RecipeTable data = new RecipeTable();
|
||||
data.Name = NameInput.Text;
|
||||
data.Mixer = false;
|
||||
data.Fountain = false;
|
||||
data.MoldHeater = false;
|
||||
data.Vibration = false;
|
||||
data.VibHeater = false;
|
||||
data.Pedal = false;
|
||||
var result = _recipeTable.AddRecipe(data);
|
||||
if (result)
|
||||
{
|
||||
addDynamicButtons();
|
||||
CloseKeyboard();
|
||||
NameInput.Text = "";
|
||||
PopupOverlay.IsVisible = false;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CloseKeyboard();
|
||||
await MainWindow.MessageBox.Show(_mainWindow, "this name is already in use", "Error");
|
||||
_mainWindow.Topmost = false;
|
||||
_mainWindow.Activate();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
private (string? fileName, string args) GetKeyboardCommand()
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
return ("osk.exe", "");
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
return ("onboard", ""); // or "florence", "matchbox-keyboard"
|
||||
return (null, "");
|
||||
}
|
||||
private async void OnTextBoxFocused(object? sender, PointerPressedEventArgs e)
|
||||
{
|
||||
if (_keyboardProcess is { HasExited: false })
|
||||
return;
|
||||
|
||||
var (fileName, args) = GetKeyboardCommand();
|
||||
if (fileName is null)
|
||||
return;
|
||||
|
||||
_keyboardProcess = new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = fileName,
|
||||
Arguments = args,
|
||||
UseShellExecute = true
|
||||
},
|
||||
EnableRaisingEvents = true
|
||||
};
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
_keyboardProcess.Start();
|
||||
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
if (sender is Border border)
|
||||
{
|
||||
var textbox= border.Child as TextBox;
|
||||
textbox.SelectionStart = 0;
|
||||
textbox.SelectionEnd = textbox.Text?.Length ?? 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch
|
||||
{
|
||||
// fail silently if keyboard not found
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPopupOverlayPointerPressed(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
// Close the popup when clicking outside of it
|
||||
recipeButton.Foreground = Avalonia.Media.Brushes.Black;
|
||||
|
||||
PopupOverlay.IsVisible = false;
|
||||
}
|
||||
|
||||
private void setDefaultSettings()
|
||||
{
|
||||
|
||||
//set recipe title
|
||||
if (_currentUser.CanEdit)
|
||||
{
|
||||
RecipeTitle.Content = "RECIPE EDIT/ADD PANEL";
|
||||
}
|
||||
else
|
||||
{
|
||||
RecipeTitle.Content = "RECIPE SELECTION";
|
||||
}
|
||||
//Set Track Up
|
||||
_mainWindow.HomeTrack.IsVisible = true;
|
||||
_mainWindow.RecipeSelTrack.IsVisible = false;
|
||||
_mainWindow.RecipePanelTrack.IsVisible = false;
|
||||
|
||||
|
||||
if (_currentUser.CanEdit)
|
||||
{
|
||||
_mainWindow.RecipePanelTrack.IsVisible = true;
|
||||
_mainWindow.RecipePanelPolygon.Stroke = Brush.Parse("#A4275D");
|
||||
}
|
||||
else
|
||||
{
|
||||
_mainWindow.RecipeSelTrack.IsVisible = true;
|
||||
_mainWindow.RecipeSelPolygon.Stroke = Brush.Parse("#A4275D");
|
||||
}
|
||||
//_mainWindow.HomePolygon.Stroke = Avalonia.Media.Brushes.Black;
|
||||
|
||||
_mainWindow.RecipeEditTrack.IsVisible = false;
|
||||
_mainWindow.RunInterfaceTrack.IsVisible = false;
|
||||
_mainWindow.SettingTrack.IsVisible = false;
|
||||
_mainWindow.TitleBtn.IsVisible = false;
|
||||
_mainWindow.DiagnosticsTrack.IsVisible = false;
|
||||
_mainWindow.SoftwareTrack.IsVisible = false;
|
||||
|
||||
|
||||
//Set Footer
|
||||
if (_currentUser.CanEdit)
|
||||
{
|
||||
_mainWindow.footerMsg.Text = "Long press to delete recipe";
|
||||
_mainWindow.footerMsg.IsVisible = true;
|
||||
_mainWindow.chefBtns.IsVisible = true;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
_mainWindow.footerMsg.Text = "Select a recipe to start";
|
||||
_mainWindow.footerMsg.IsVisible = true;
|
||||
|
||||
|
||||
}
|
||||
_mainWindow.ManualControlTrack.IsVisible = false;
|
||||
|
||||
_mainWindow.footerMsg.MaxWidth = 1000;
|
||||
|
||||
_mainWindow.footer.Background = Avalonia.Media.Brushes.WhiteSmoke;
|
||||
_mainWindow.footerMsg.Foreground = Brush.Parse("#A4275D");
|
||||
_mainWindow.footerDate.Text = DateTime.Now.ToString("dd/MM/yyyy");
|
||||
_mainWindow.footerTime.Text = DateTime.Now.ToString("hh:mm tt");
|
||||
_mainWindow.footerDateContainer.IsVisible = true;
|
||||
_mainWindow.footerStartBtn.IsVisible = false;
|
||||
_mainWindow.adminBtns.IsVisible = false;
|
||||
}
|
||||
private void addDynamicButtons()
|
||||
{
|
||||
var recipes= _recipeTable.ReadRecipes();
|
||||
var grid = this.FindControl<Grid>("DynamicGrid");
|
||||
grid.Children.Clear();
|
||||
int lastRow = 0;
|
||||
int lastCol = 0;
|
||||
int colIndexForExtraData = 0;
|
||||
int recipeIndex = 0;
|
||||
|
||||
try
|
||||
{
|
||||
if (recipes.Count<3)
|
||||
{
|
||||
// Add dynamic rows
|
||||
for (int i = 0; i < (int)Math.Ceiling((double)recipes.Count / 3); i++) // Example: 20 rows
|
||||
{
|
||||
lastRow = i;
|
||||
grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
|
||||
|
||||
// Add content for each column
|
||||
for (int col = 0; col < recipes.Count; col++)
|
||||
{
|
||||
|
||||
lastCol = col;
|
||||
|
||||
var text = new TextBlock
|
||||
{
|
||||
Padding = new Thickness(10),
|
||||
Text = recipes[recipeIndex + col].Name,
|
||||
VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center,
|
||||
HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center,
|
||||
FontSize = 31,
|
||||
FontWeight=FontWeight.Normal,
|
||||
Foreground = Avalonia.Media.Brushes.Black
|
||||
|
||||
};
|
||||
var button = new Button
|
||||
{
|
||||
Width = 210,
|
||||
Height = 160,
|
||||
Margin = new Thickness(3),
|
||||
Content = text,
|
||||
Name = recipes[recipeIndex + col].Id.ToString(),
|
||||
CornerRadius = new CornerRadius(10),
|
||||
Background = Avalonia.Media.Brushes.White,
|
||||
HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center,
|
||||
VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center,
|
||||
|
||||
};
|
||||
|
||||
button.Click += OnRecipeClick;
|
||||
|
||||
if (_currentUser.CanEdit)
|
||||
{
|
||||
//button.Holding += OnLongRecipeClick;
|
||||
AttachHandlers(button);
|
||||
//button.DoubleTapped += OnDoubleRecipeClick;
|
||||
|
||||
}
|
||||
|
||||
grid.Children.Add(button);
|
||||
Grid.SetRow(button, i);
|
||||
Grid.SetColumn(button, col);
|
||||
}
|
||||
recipeIndex += 3;
|
||||
}
|
||||
if (_currentUser.CanEdit)
|
||||
{
|
||||
var Plus = new TextBlock
|
||||
{
|
||||
Padding = new Thickness(10),
|
||||
Text = "+",
|
||||
VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center,
|
||||
HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center,
|
||||
FontSize = 100,
|
||||
Foreground = Brush.Parse("#A4275D")
|
||||
|
||||
};
|
||||
var AddButtun = new Button
|
||||
{
|
||||
Width = 210,
|
||||
Height = 160,
|
||||
Margin = new Thickness(3),
|
||||
Content = Plus,
|
||||
CornerRadius = new CornerRadius(10),
|
||||
Background = Avalonia.Media.Brushes.White,
|
||||
HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center,
|
||||
VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center,
|
||||
VerticalContentAlignment = Avalonia.Layout.VerticalAlignment.Center,
|
||||
HorizontalContentAlignment = Avalonia.Layout.HorizontalAlignment.Center,
|
||||
Padding = new Thickness(0, 0, 0, 15),
|
||||
|
||||
};
|
||||
AddButtun.Click += OnAddRecipeClick;
|
||||
if (lastCol < 2)
|
||||
{
|
||||
grid.Children.Add(AddButtun);
|
||||
Grid.SetRow(AddButtun, lastRow);
|
||||
Grid.SetColumn(AddButtun, lastCol + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
|
||||
|
||||
grid.Children.Add(AddButtun);
|
||||
Grid.SetRow(AddButtun, lastRow + 1);
|
||||
Grid.SetColumn(AddButtun, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add dynamic rows
|
||||
for (int i = 0; i < (int)Math.Floor((double)recipes.Count / 3); i++) // Example: 20 rows
|
||||
{
|
||||
lastRow = i;
|
||||
grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
|
||||
|
||||
// Add content for each column
|
||||
for (int col = 0; col < 3; col++)
|
||||
{
|
||||
|
||||
|
||||
lastCol = col;
|
||||
|
||||
var text = new TextBlock
|
||||
{
|
||||
Padding = new Thickness(10),
|
||||
Text = recipes[recipeIndex + col].Name,
|
||||
VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center,
|
||||
HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center,
|
||||
FontSize = 31,
|
||||
FontWeight = FontWeight.Normal,
|
||||
Foreground = Avalonia.Media.Brushes.Black
|
||||
|
||||
};
|
||||
var button = new Button
|
||||
{
|
||||
Width = 210,
|
||||
Height = 160,
|
||||
Margin = new Thickness(3),
|
||||
Content = text,
|
||||
Name = recipes[recipeIndex + col].Id.ToString(),
|
||||
CornerRadius = new CornerRadius(10),
|
||||
Background = Avalonia.Media.Brushes.White,
|
||||
HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center,
|
||||
VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center,
|
||||
|
||||
};
|
||||
button.Click += OnRecipeClick;
|
||||
|
||||
if (_currentUser.CanEdit)
|
||||
{
|
||||
//button.Holding += OnLongRecipeClick;
|
||||
AttachHandlers(button);
|
||||
|
||||
//button.DoubleTapped += OnDoubleRecipeClick;
|
||||
|
||||
}
|
||||
|
||||
grid.Children.Add(button);
|
||||
Grid.SetRow(button, i);
|
||||
Grid.SetColumn(button, col);
|
||||
}
|
||||
recipeIndex += 3;
|
||||
}
|
||||
for (int i = 0; i < recipes.Count -recipeIndex; i++)
|
||||
{
|
||||
var text = new TextBlock
|
||||
{
|
||||
Padding = new Thickness(10),
|
||||
Text = recipes[recipeIndex + i].Name,
|
||||
VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center,
|
||||
HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center,
|
||||
FontSize = 31,
|
||||
FontWeight = FontWeight.Normal,
|
||||
Foreground = Avalonia.Media.Brushes.Black
|
||||
|
||||
};
|
||||
var button = new Button
|
||||
{
|
||||
Width = 210,
|
||||
Height = 160,
|
||||
Margin = new Thickness(3),
|
||||
Content = text,
|
||||
Name = recipes[recipeIndex + i].Id.ToString(),
|
||||
CornerRadius = new CornerRadius(10),
|
||||
Background = Avalonia.Media.Brushes.White,
|
||||
HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center,
|
||||
VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center,
|
||||
|
||||
};
|
||||
button.Click += OnRecipeClick;
|
||||
|
||||
if (_currentUser.CanEdit)
|
||||
{
|
||||
//button.Holding += OnLongRecipeClick;
|
||||
AttachHandlers(button);
|
||||
|
||||
//button.DoubleTapped += OnDoubleRecipeClick;
|
||||
|
||||
}
|
||||
if (lastCol < 2)
|
||||
{
|
||||
lastCol += 1;
|
||||
|
||||
|
||||
|
||||
|
||||
grid.Children.Add(button);
|
||||
Grid.SetRow(button,lastRow);
|
||||
Grid.SetColumn(button, lastCol);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
|
||||
|
||||
grid.Children.Add(button);
|
||||
Grid.SetRow(button, lastRow + 1);
|
||||
Grid.SetColumn(button, colIndexForExtraData);
|
||||
colIndexForExtraData += 1;
|
||||
}
|
||||
}
|
||||
if (_currentUser.CanEdit)
|
||||
{
|
||||
var Plus = new TextBlock
|
||||
{
|
||||
Padding = new Thickness(10),
|
||||
Text = "+",
|
||||
VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center,
|
||||
HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center,
|
||||
FontSize = 100,
|
||||
Foreground = Brush.Parse("#A4275D"),
|
||||
|
||||
|
||||
};
|
||||
var AddButtun = new Button
|
||||
{
|
||||
Width = 210,
|
||||
Height = 160,
|
||||
Margin = new Thickness(3),
|
||||
Content = Plus,
|
||||
CornerRadius = new CornerRadius(10),
|
||||
Background = Avalonia.Media.Brushes.White,
|
||||
VerticalContentAlignment = Avalonia.Layout.VerticalAlignment.Center,
|
||||
HorizontalContentAlignment = Avalonia.Layout.HorizontalAlignment.Center,
|
||||
HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center,
|
||||
VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center,
|
||||
Padding = new Thickness(0,0,0,15),
|
||||
};
|
||||
|
||||
AddButtun.Click += OnAddRecipeClick;
|
||||
|
||||
if (lastCol < 2)
|
||||
{
|
||||
grid.Children.Add(AddButtun);
|
||||
Grid.SetRow(AddButtun, lastRow);
|
||||
Grid.SetColumn(AddButtun, lastCol + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
|
||||
|
||||
grid.Children.Add(AddButtun);
|
||||
Grid.SetRow(AddButtun, lastRow + 1);
|
||||
Grid.SetColumn(AddButtun, colIndexForExtraData);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
232
DaireApplication/Views/UserController/RecipeEdit.axaml
Normal file
@@ -0,0 +1,232 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
x:Class="DaireApplication.RecipeEdit"
|
||||
Width="1200"
|
||||
mc:Ignorable="d" >
|
||||
<Grid>
|
||||
<!-- Main Content (machine picture on left, etc.) -->
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="2*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<!-- Machine Picture on Left -->
|
||||
<Grid Grid.Column="0">
|
||||
<Grid x:Name="machinePic" IsVisible="True" Width="937" Height="567">
|
||||
<Grid.Background>
|
||||
<ImageBrush Source="/Assets/TemperingGraphics.png"/>
|
||||
</Grid.Background>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<!-- (Optional additional content on right if needed) -->
|
||||
</Grid>
|
||||
|
||||
<!-- Popup Overlay -->
|
||||
<Border x:Name="PopupOverlay"
|
||||
Background="#80000000"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
IsVisible="False"
|
||||
ZIndex="50"
|
||||
PointerPressed="OnPopupOverlayPointerPressed">
|
||||
<Grid MaxWidth="500" MaxHeight="500" HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<Border x:Name="PopupControl"
|
||||
BorderThickness="2"
|
||||
CornerRadius="10"
|
||||
Padding="10"
|
||||
PointerPressed="OnPopupOverlayPointerPressed">
|
||||
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Spacing="10">
|
||||
<!-- Popup Content (Keypad etc.) -->
|
||||
<Grid IsVisible="True">
|
||||
<Grid.Styles>
|
||||
<Style Selector="Button">
|
||||
<Setter Property="Background" Value="White"/>
|
||||
<Setter Property="CornerRadius" Value="20"/>
|
||||
<Setter Property="Width" Value="100"/>
|
||||
<Setter Property="Height" Value="100"/>
|
||||
<Setter Property="FontSize" Value="50"/>
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Center"/>
|
||||
</Style>
|
||||
<Style Selector="Button:pointerover /template/ContentPresenter">
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
<Setter Property="Background" Value="White"/>
|
||||
<Setter Property="CornerRadius" Value="20"/>
|
||||
<Setter Property="RenderTransform" Value="scale(1.11)"/>
|
||||
</Style>
|
||||
</Grid.Styles>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.Row="1" Margin="10">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="1*"/>
|
||||
<RowDefinition Height="1*"/>
|
||||
<RowDefinition Height="1*"/>
|
||||
<RowDefinition Height="1*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<!-- Keypad Buttons -->
|
||||
<Button Content="1" Grid.Row="0" Grid.Column="0" FontSize="24" Background="White" Margin="5" Click="OnKeyClick"/>
|
||||
<Button Content="2" Grid.Row="0" Grid.Column="1" FontSize="24" Background="White" Margin="5" Click="OnKeyClick"/>
|
||||
<Button Content="3" Grid.Row="0" Grid.Column="2" FontSize="24" Background="White" Margin="5" Click="OnKeyClick"/>
|
||||
<Button Content="4" Grid.Row="1" Grid.Column="0" FontSize="24" Background="White" Margin="5" Click="OnKeyClick"/>
|
||||
<Button Content="5" Grid.Row="1" Grid.Column="1" FontSize="24" Background="White" Margin="5" Click="OnKeyClick"/>
|
||||
<Button Content="6" Grid.Row="1" Grid.Column="2" FontSize="24" Background="White" Margin="5" Click="OnKeyClick"/>
|
||||
<Button Content="7" Grid.Row="2" Grid.Column="0" FontSize="24" Background="White" Margin="5" Click="OnKeyClick"/>
|
||||
<Button Content="8" Grid.Row="2" Grid.Column="1" FontSize="24" Background="White" Margin="5" Click="OnKeyClick"/>
|
||||
<Button Content="9" Grid.Row="2" Grid.Column="2" FontSize="24" Background="White" Margin="5" Click="OnKeyClick"/>
|
||||
<Button Content="BACK" Grid.Row="3" Grid.Column="0" FontSize="20" Background="#D3D3D3" Margin="5" Click="OnBackClick"/>
|
||||
<Button Content="0" Grid.Row="3" Grid.Column="1" FontSize="24" Background="White" Margin="5" Click="OnKeyClick"/>
|
||||
<Button Content="ENTER" Grid.Row="3" Grid.Column="2" FontSize="20" Background="#A4275D" Foreground="White" Margin="5" Click="EnterClick"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- Overlay Container for the Three Buttons (always at the right side) -->
|
||||
<StackPanel x:Name="ButtonOverlayContainer"
|
||||
Orientation="Vertical"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Margin="0,0,20,20"
|
||||
Spacing="20"
|
||||
ZIndex="100"
|
||||
>
|
||||
<Border CornerRadius="10"
|
||||
Background="White"
|
||||
Padding="20"
|
||||
Margin="20"
|
||||
Width="270"
|
||||
Height="400" ZIndex="49" >
|
||||
<!-- Use a Grid with RowDefinitions to position elements -->
|
||||
<Grid ZIndex="49">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<!-- First button -->
|
||||
<RowDefinition Height="9*" />
|
||||
<!-- Spacer to push content to bottom -->
|
||||
<RowDefinition Height="Auto" />
|
||||
<!-- Second button -->
|
||||
<RowDefinition Height="3*" />
|
||||
<!-- Spacer to push content to bottom -->
|
||||
<RowDefinition Height="Auto" />
|
||||
<!-- Third button -->
|
||||
<RowDefinition Height="7*" />
|
||||
<!-- Spacer to push content to bottom -->
|
||||
<RowDefinition Height="Auto" />
|
||||
<!-- Arrow + label at bottom -->
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.Styles>
|
||||
|
||||
<Style Selector="Button:pointerover /template/ContentPresenter">
|
||||
<Setter Property="Foreground" Value="Black"></Setter>
|
||||
<Setter Property="Background" Value="LightGray"></Setter>
|
||||
|
||||
|
||||
|
||||
</Style>
|
||||
|
||||
|
||||
</Grid.Styles>
|
||||
|
||||
<Grid.Styles>
|
||||
<Style Selector="Button:disabled /template/ContentPresenter" >
|
||||
<Setter Property="Background" Value="Gray"/>
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
</Style>
|
||||
</Grid.Styles>
|
||||
<!-- Red Button for Heating -->
|
||||
|
||||
<Button Grid.Row="0" x:Name="heatingBtn"
|
||||
Background="#FFFF5252"
|
||||
Foreground="White"
|
||||
FontSize="25"
|
||||
Padding="10,5"
|
||||
BorderThickness="0"
|
||||
Width="230"
|
||||
HorizontalAlignment="Center"
|
||||
HorizontalContentAlignment="Center"
|
||||
CornerRadius="10"
|
||||
Click="showPopUp"
|
||||
>
|
||||
<StackPanel Spacing="5" Orientation="Horizontal">
|
||||
<TextBlock>HEATING: </TextBlock>
|
||||
<TextBlock x:Name="heatingValue"></TextBlock>
|
||||
<TextBlock> °C</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
</Button>
|
||||
<TextBlock Grid.Row="1" TextWrapping="WrapWithOverflow" VerticalAlignment="Center" FontWeight="Normal" FontSize="14" Foreground="Red" x:Name="tempErrorMsg">
|
||||
</TextBlock>
|
||||
|
||||
<!-- Brown Button for Pouring -->
|
||||
<Button Grid.Row="2" x:Name="pouringBtn"
|
||||
Background="#FF795548"
|
||||
Foreground="White"
|
||||
FontSize="25"
|
||||
Padding="10,5"
|
||||
BorderThickness="0"
|
||||
Width="230"
|
||||
HorizontalAlignment="Center"
|
||||
HorizontalContentAlignment="Center"
|
||||
CornerRadius="10"
|
||||
Click="showPopUp" >
|
||||
<StackPanel Spacing="5" Orientation="Horizontal">
|
||||
<TextBlock>POURING: </TextBlock>
|
||||
<TextBlock x:Name="pouringValue"></TextBlock>
|
||||
<TextBlock> °C</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<!-- Blue Button for Cooling -->
|
||||
<Button Grid.Row="4" x:Name="coolingBtn"
|
||||
Classes="NotEnabled"
|
||||
FontSize="25"
|
||||
Background="#FF448AFF"
|
||||
Foreground="White"
|
||||
Padding="10,5"
|
||||
BorderThickness="0"
|
||||
Width="230"
|
||||
HorizontalAlignment="Center"
|
||||
CornerRadius="10"
|
||||
HorizontalContentAlignment="Center"
|
||||
Click="showPopUp" >
|
||||
<StackPanel Spacing="5" Orientation="Horizontal">
|
||||
<TextBlock>COOLING: </TextBlock>
|
||||
<TextBlock x:Name="coolingValue"></TextBlock>
|
||||
<TextBlock> °C</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
</Button>
|
||||
|
||||
|
||||
<!-- Arrow and 'EDIT HERE' Label at the Bottom -->
|
||||
<StackPanel Grid.Row="6" HorizontalAlignment="Center">
|
||||
<TextBlock Text="↑"
|
||||
FontSize="50"
|
||||
FontWeight="Normal"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="Black"/>
|
||||
<TextBlock Text="EDIT HERE"
|
||||
FontSize="30"
|
||||
FontWeight="Normal"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="Black"
|
||||
/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
253
DaireApplication/Views/UserController/RecipeEdit.axaml.cs
Normal file
@@ -0,0 +1,253 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.Media;
|
||||
using AvaloniaApplication1.DataBase;
|
||||
using DaireApplication.Views;
|
||||
using System;
|
||||
|
||||
namespace DaireApplication;
|
||||
|
||||
public partial class RecipeEdit : UserControl
|
||||
{
|
||||
Button controllButton = new Button();
|
||||
private MainWindow? _mainWindow;
|
||||
private UserTable? _currentUser;
|
||||
private RecipeTable? _recipeTable;
|
||||
|
||||
|
||||
public RecipeEdit()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
public RecipeEdit(MainWindow mainWindow, UserTable currentUser,RecipeTable recipeTable)
|
||||
{
|
||||
_currentUser = currentUser;
|
||||
_mainWindow = mainWindow;
|
||||
_recipeTable=recipeTable;
|
||||
InitializeComponent();
|
||||
setDefaultSettings();
|
||||
}
|
||||
|
||||
string oldNumber = "";
|
||||
private void OnKeyClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Button button)
|
||||
{
|
||||
|
||||
var StackPanel = controllButton.Content as StackPanel;
|
||||
var Label = StackPanel.Children;
|
||||
if (Label[1] is TextBlock targetText)
|
||||
{
|
||||
//number += button.Content?.ToString();
|
||||
targetText.Text += button.Content ;
|
||||
}
|
||||
// Append the button's content to the input box
|
||||
//InputTextBox.Text += button.Content?.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
private void OnBackClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var StackPanel = controllButton.Content as StackPanel;
|
||||
var Label = StackPanel.Children;
|
||||
if (Label[1] is TextBlock targetText)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(targetText.Text))
|
||||
{
|
||||
// Remove the last character from the text box
|
||||
targetText.Text = targetText.Text.Remove(targetText.Text.Length -1, 1);
|
||||
//number = number.Remove(number.Length - 1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
private void EnterClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
// <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||||
RecipeTable recipe = new RecipeTable
|
||||
{
|
||||
Id = _recipeTable.Id,
|
||||
Name = _recipeTable.Name,
|
||||
TankTemp = _recipeTable.TankTemp,
|
||||
FountainTemp = _recipeTable.FountainTemp,
|
||||
Mixer = _recipeTable.Mixer ?? false,
|
||||
Fountain = _recipeTable.Fountain ?? false,
|
||||
MoldHeater = _recipeTable.MoldHeater ?? false,
|
||||
Vibration = _recipeTable.Vibration ?? false,
|
||||
VibHeater = _recipeTable.VibHeater ?? false,
|
||||
Pedal = _recipeTable.Pedal ?? false,
|
||||
PedalOnTime = _recipeTable.PedalOnTime,
|
||||
PedalOffTime = _recipeTable.PedalOffTime,
|
||||
HeatingGoal = _recipeTable.HeatingGoal,
|
||||
CoolingGoal = _recipeTable.CoolingGoal,
|
||||
PouringGoal = _recipeTable.PouringGoal
|
||||
};
|
||||
|
||||
var heatingStackPanel = heatingBtn.Content as StackPanel;
|
||||
var heatingText = (heatingStackPanel?.Children[1] as TextBlock)?.Text;
|
||||
|
||||
var coolingStackPanel = coolingBtn.Content as StackPanel;
|
||||
var coolingText = (coolingStackPanel?.Children[1] as TextBlock)?.Text;
|
||||
|
||||
var stackPanel = controllButton.Content as StackPanel;
|
||||
var label = stackPanel?.Children;
|
||||
var targetText = label?[1] as TextBlock;
|
||||
var activeTxt = label?[0] as TextBlock;
|
||||
|
||||
if (activeTxt == null || targetText == null)
|
||||
return;
|
||||
|
||||
switch (activeTxt.Text)
|
||||
{
|
||||
case "HEATING:":
|
||||
if (!string.IsNullOrEmpty(targetText.Text) && int.TryParse(targetText.Text, out int heatingValue))
|
||||
{
|
||||
if (heatingValue > 60)
|
||||
{
|
||||
tempErrorMsg.Text = "Heating Temperature must be lower than 60 <20>C";
|
||||
return;
|
||||
}
|
||||
else if (heatingValue < 40)
|
||||
{
|
||||
tempErrorMsg.Text = "Heating Temperature must be greater than 40 <20>C";
|
||||
return;
|
||||
}
|
||||
|
||||
recipe.HeatingGoal = heatingValue;
|
||||
}
|
||||
break;
|
||||
|
||||
case "POURING:":
|
||||
if (!string.IsNullOrEmpty(targetText.Text) && int.TryParse(targetText.Text, out int pouringValue))
|
||||
{
|
||||
if (string.IsNullOrEmpty(heatingText) || string.IsNullOrEmpty(coolingText))
|
||||
{
|
||||
tempErrorMsg.Text = "Enter heating and cooling temperature first";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!int.TryParse(heatingText, out int heatingTemp) || !int.TryParse(coolingText, out int coolingTemp))
|
||||
{
|
||||
tempErrorMsg.Text = "Invalid temperature values";
|
||||
return;
|
||||
}
|
||||
|
||||
if (pouringValue > heatingTemp)
|
||||
{
|
||||
tempErrorMsg.Text = $"Pouring Temperature must be lower than Heating Temperature ({heatingTemp}<7D>C)";
|
||||
return;
|
||||
}
|
||||
else if (pouringValue < coolingTemp)
|
||||
{
|
||||
tempErrorMsg.Text = $"Pouring Temperature must be greater than Cooling Temperature ({coolingTemp}<7D>C)";
|
||||
return;
|
||||
}
|
||||
|
||||
recipe.PouringGoal = pouringValue;
|
||||
}
|
||||
break;
|
||||
|
||||
case "COOLING:":
|
||||
if (!string.IsNullOrEmpty(targetText.Text) && int.TryParse(targetText.Text, out int coolingValue))
|
||||
{
|
||||
if (coolingValue > 40)
|
||||
{
|
||||
tempErrorMsg.Text = "Cooling Temperature must be lower than 40 <20>C";
|
||||
return;
|
||||
}
|
||||
else if (coolingValue < 20)
|
||||
{
|
||||
tempErrorMsg.Text = "Cooling Temperature must be greater than 20 <20>C";
|
||||
return;
|
||||
}
|
||||
|
||||
recipe.CoolingGoal = coolingValue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
_recipeTable.UpdateRecipe(recipe);
|
||||
tempErrorMsg.Text = "";
|
||||
heatingBtn.IsEnabled = true;
|
||||
coolingBtn.IsEnabled = true;
|
||||
pouringBtn.IsEnabled = true;
|
||||
PopupOverlay.IsVisible = false;
|
||||
setDefaultSettings();
|
||||
}
|
||||
|
||||
|
||||
private void showPopUp(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Button button)
|
||||
{
|
||||
heatingBtn.IsEnabled = false;
|
||||
coolingBtn.IsEnabled = false;
|
||||
pouringBtn.IsEnabled = false;
|
||||
button.IsEnabled = true;
|
||||
var StackPanel = button.Content as StackPanel;
|
||||
var Label = StackPanel.Children;
|
||||
if (Label[1] is TextBlock targetText)
|
||||
{
|
||||
oldNumber = targetText.Text;
|
||||
}
|
||||
controllButton = button;
|
||||
PopupOverlay.IsVisible = true;
|
||||
}
|
||||
|
||||
}
|
||||
private void OnPopupOverlayPointerPressed(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
// Close the popup when clicking outside of it
|
||||
//controllButton.Foreground = Avalonia.Media.Brushes.Black;
|
||||
var StackPanel = controllButton.Content as StackPanel;
|
||||
var Label = StackPanel.Children;
|
||||
if (Label[1] is TextBlock targetText)
|
||||
{
|
||||
//number += button.Content?.ToString();
|
||||
targetText.Text = oldNumber;
|
||||
}
|
||||
tempErrorMsg.Text = "";
|
||||
heatingBtn.IsEnabled = true;
|
||||
coolingBtn.IsEnabled = true;
|
||||
pouringBtn.IsEnabled = true;
|
||||
|
||||
PopupOverlay.IsVisible = false;
|
||||
}
|
||||
|
||||
private void setDefaultSettings()
|
||||
{
|
||||
//set Values
|
||||
_recipeTable = _recipeTable.ReadRecipesById(_recipeTable.Id.ToString());
|
||||
heatingValue.Text = _recipeTable?.HeatingGoal == 0 ? "" : _recipeTable?.HeatingGoal.ToString();
|
||||
coolingValue.Text = _recipeTable?.CoolingGoal == 0 ? "" : _recipeTable?.CoolingGoal.ToString();
|
||||
pouringValue.Text = _recipeTable?.PouringGoal == 0 ? "" : _recipeTable?.PouringGoal.ToString();
|
||||
|
||||
//Set Track Up
|
||||
_mainWindow.HomeTrack.IsVisible = true;
|
||||
//_mainWindow.HomePolygon.Stroke = Avalonia.Media.Brushes.Black;
|
||||
_mainWindow.RecipePanelTrack.IsVisible = true;
|
||||
_mainWindow.RecipePanelPolygon.Stroke = Avalonia.Media.Brushes.Black;
|
||||
_mainWindow.RecipeEditTrack.IsVisible = true;
|
||||
_mainWindow.RecipeEditPolygon.Stroke = Brush.Parse("#A4275D");
|
||||
_mainWindow.RunInterfaceTrack.IsVisible = false;
|
||||
_mainWindow.RecipeSelTrack.IsVisible = false;
|
||||
_mainWindow.SettingTrack.IsVisible = false;
|
||||
_mainWindow.DiagnosticsTrack.IsVisible = false;
|
||||
|
||||
_mainWindow.TitleBtn.IsVisible = true;
|
||||
_mainWindow.Title.Text = _recipeTable.Name;
|
||||
|
||||
//Set Footer
|
||||
_mainWindow.footerMsg.Text = "Select the tempereture to edit it";
|
||||
_mainWindow.footer.Background = Avalonia.Media.Brushes.WhiteSmoke;
|
||||
_mainWindow.footerMsg.Foreground = Brush.Parse("#A4275D");
|
||||
_mainWindow.footerDate.Text = DateTime.Now.ToString("dd/MM/yyyy");
|
||||
_mainWindow.footerTime.Text = DateTime.Now.ToString("hh:mm tt");
|
||||
_mainWindow.footerDateContainer.IsVisible = true;
|
||||
_mainWindow.footerStartBtn.IsVisible = false;
|
||||
_mainWindow.adminBtns.IsVisible = false;
|
||||
}
|
||||
}
|
||||
513
DaireApplication/Views/UserController/Settings.axaml
Normal file
@@ -0,0 +1,513 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
Width="1200"
|
||||
Height="620"
|
||||
Background="#b3b3b3"
|
||||
x:Class="DaireApplication.Settings" FontFamily="Helvetica" >
|
||||
<Grid RowDefinitions="*">
|
||||
<!-- Main Area-->
|
||||
<Grid Grid.Row="0">
|
||||
<Grid.Styles>
|
||||
<Style Selector="Button">
|
||||
<Setter Property="Background" Value="#F9F9F9"></Setter>
|
||||
<Setter Property="CornerRadius" Value="50"></Setter>
|
||||
<Setter Property="Width" Value="150"></Setter>
|
||||
<Setter Property="Height" Value="90"></Setter>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"></Setter>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Center"></Setter>
|
||||
</Style>
|
||||
|
||||
<Style Selector="Button:pointerover /template/ContentPresenter">
|
||||
<Setter Property="Background" Value="#F9F9F9"></Setter>
|
||||
|
||||
</Style>
|
||||
<Style Selector="Button.SpecialButtonStyle:pointerover /template/ContentPresenter" >
|
||||
<Setter Property="Background" Value="#E6E6E6"/>
|
||||
<Setter Property="CornerRadius" Value="25"/>
|
||||
</Style>
|
||||
|
||||
</Grid.Styles>
|
||||
|
||||
<Grid ColumnDefinitions="2*,1.4*,2.2*" >
|
||||
<Grid Grid.Column="0" RowDefinitions="*,Auto,*,*" >
|
||||
<Grid Grid.Row="1" Margin="5,0,0,0">
|
||||
<StackPanel>
|
||||
<TextBlock FontSize="18" TextWrapping="WrapWithOverflow" x:Name="mixerDelayTxt"
|
||||
IsVisible="False"
|
||||
Foreground="Black">Mixer
|
||||
Delay: </TextBlock>
|
||||
<TextBlock FontSize="25"
|
||||
Margin="50,0,0,0"
|
||||
x:Name="mixerDelayCounter"
|
||||
IsVisible="False"
|
||||
TextWrapping="WrapWithOverflow"
|
||||
Foreground="Black">120</TextBlock>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
</Grid>
|
||||
<Grid Grid.Row="3" Margin="5,40,0,0">
|
||||
<StackPanel>
|
||||
<TextBlock FontSize="18" TextWrapping="WrapWithOverflow" x:Name="pedalDelayTxt"
|
||||
IsVisible="False"
|
||||
Foreground="Black">
|
||||
Pedal OFF:
|
||||
</TextBlock>
|
||||
<TextBlock FontSize="25"
|
||||
Margin="50,0,0,0"
|
||||
x:Name="pedalDelayCounter"
|
||||
IsVisible="False"
|
||||
TextWrapping="WrapWithOverflow"
|
||||
Foreground="Black">120</TextBlock>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
</Grid>
|
||||
<StackPanel>
|
||||
<TextBlock FontSize="18" TextWrapping="WrapWithOverflow" x:Name="coolingDelayTxt"
|
||||
IsVisible="False"
|
||||
Foreground="Black">Cooling Delay: </TextBlock>
|
||||
<TextBlock FontSize="25"
|
||||
Margin="50,0,0,0"
|
||||
x:Name="coolingDelayCounter"
|
||||
IsVisible="False"
|
||||
TextWrapping="WrapWithOverflow"
|
||||
Foreground="Black">120</TextBlock>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<Grid Grid.Column="2"
|
||||
RowDefinitions="*,Auto,*,*" ZIndex="200"
|
||||
Margin="0,0,0,0" >
|
||||
<Grid Grid.Row="1" Margin="305,0,0,0" ZIndex="200">
|
||||
<StackPanel>
|
||||
<TextBlock FontSize="18" TextWrapping="" x:Name="fountainDelayTxt"
|
||||
IsVisible="False"
|
||||
Foreground="Black">Fountain Delay: </TextBlock>
|
||||
<TextBlock FontSize="25"
|
||||
Margin="50,0,0,0"
|
||||
IsVisible="False"
|
||||
Foreground="Black"
|
||||
x:Name="fountainDelayCounter"
|
||||
TextWrapping="WrapWithOverflow">120</TextBlock>
|
||||
|
||||
<TextBlock FontSize="18" TextWrapping="" x:Name="fountainTargetTxt"
|
||||
IsVisible="False"
|
||||
Foreground="Black">Target Temp: </TextBlock>
|
||||
<TextBlock FontSize="25"
|
||||
Margin="50,0,0,0"
|
||||
IsVisible="False"
|
||||
Foreground="Black"
|
||||
x:Name="fountainTagetTemp"
|
||||
TextWrapping="WrapWithOverflow">120</TextBlock>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid HorizontalAlignment="Center" Grid.Column="0" VerticalAlignment="Center" RowDefinitions="*,7*" Margin="40,0,0,20" ZIndex="100">
|
||||
|
||||
|
||||
<StackPanel Grid.Row="1" Orientation="Vertical" >
|
||||
<!--Tank Temp -->
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" >
|
||||
|
||||
|
||||
<Button IsEnabled="False" Margin="10" CornerRadius="10" >
|
||||
<Button.Styles>
|
||||
<!-- Custom Style for Disabled Button -->
|
||||
<Style Selector="Button:disabled /template/ContentPresenter">
|
||||
<Setter Property="Background" Value="#E6E6E6"/>
|
||||
<Setter Property="Foreground" Value="#231F20"/>
|
||||
|
||||
</Style>
|
||||
</Button.Styles>
|
||||
<StackPanel Width="150" Height="90" Spacing="5">
|
||||
<Label CornerRadius="25" FontSize="15.5"
|
||||
FontWeight="Normal" Foreground="#8D8D8D" HorizontalContentAlignment="Center"
|
||||
Margin="0,5,0,-5">TANK TEMP</Label>
|
||||
<StackPanel
|
||||
Spacing="-10"
|
||||
Orientation="Horizontal"
|
||||
Margin="0,-5,0,0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center">
|
||||
<Label x:Name="TankTempValue" FontSize="35" FontWeight="Normal"
|
||||
HorizontalContentAlignment="Center"
|
||||
VerticalContentAlignment="Center">-100.0</Label>
|
||||
<Label FontSize="40" FontWeight="Normal" >°C</Label>
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
<!--Mixer -->
|
||||
<StackPanel Orientation="Horizontal" >
|
||||
|
||||
<Button x:Name="mixerBtn" CornerRadius="10" Margin="10" >
|
||||
<StackPanel x:Name="MixerSP">
|
||||
<Label FontSize="15.5" FontWeight="Normal" HorizontalContentAlignment="Center" Foreground="#666666">MIXER</Label>
|
||||
<Label FontSize="47" FontWeight="Normal" HorizontalContentAlignment="Center" Foreground="#ff231f20" Margin="0,-15,0,0">OFF</Label>
|
||||
<!-- Underline -->
|
||||
<Rectangle Fill="#666666" Height="5" Width="110" Margin="0,-15,0,0"></Rectangle>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
<!--Recipe Setting -->
|
||||
<StackPanel Orientation="Horizontal" x:Name="recipeSettings" >
|
||||
|
||||
<Button CornerRadius="10" Margin="10" Padding="0">
|
||||
<StackPanel Spacing="-7">
|
||||
<Label FontSize="15" HorizontalContentAlignment="Center" Foreground="#AF196F" Margin="0,0,0,1">RECIPE SETTINGS</Label>
|
||||
|
||||
<Grid RowDefinitions="*">
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto">
|
||||
<Label Grid.Column="0" FontSize="15" FontWeight="Normal" HorizontalContentAlignment="Center" Foreground="#000000">Heating:</Label>
|
||||
<Label Grid.Column="1" x:Name="heatingValue" FontSize="15" FontWeight="Normal" HorizontalContentAlignment="Center" Foreground="#000000">47.0</Label>
|
||||
<Label Grid.Column="2" FontSize="15" FontWeight="Normal" HorizontalContentAlignment="Center" Foreground="#000000">°C</Label>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid RowDefinitions="*">
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto">
|
||||
<Label Grid.Column="0" FontSize="15" FontWeight="Normal" HorizontalContentAlignment="Center" Foreground="#000000">Pouring:</Label>
|
||||
<Label Grid.Column="1" x:Name="pouringValue" FontSize="15" FontWeight="Normal" HorizontalContentAlignment="Center" Foreground="#000000">47.0</Label>
|
||||
<Label Grid.Column="2" FontSize="15" FontWeight="Normal" HorizontalContentAlignment="Center" Foreground="#000000">°C</Label>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid RowDefinitions="*">
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto">
|
||||
<Label Grid.Column="0" FontSize="15" FontWeight="Normal" HorizontalContentAlignment="Center" Foreground="#000000">Cooling:</Label>
|
||||
<Label Grid.Column="1" x:Name="coolingValue" FontSize="15" FontWeight="Normal" HorizontalContentAlignment="Center" Foreground="#000000">47.0</Label>
|
||||
<Label Grid.Column="2" FontSize="15" FontWeight="Normal" HorizontalContentAlignment="Center" Foreground="#000000">°C</Label>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<StackPanel Orientation="Horizontal">
|
||||
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
<StackPanel HorizontalAlignment="Center" Width="150" Height="200">
|
||||
|
||||
<!-- Pedal Container -->
|
||||
<Button Background="#F9F9F9" CornerRadius="10" Width="150" Height="200" VerticalContentAlignment="Center" HorizontalContentAlignment="Center">
|
||||
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" Height="200" Width="150">
|
||||
|
||||
<!-- Pedal Title -->
|
||||
<TextBlock Margin="7" Text="PEDAL" FontSize="15" FontWeight="Normal"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Center" Foreground="#666666" />
|
||||
|
||||
<!-- Auto Mode Button -->
|
||||
<Button Background="#E6E6E6" CornerRadius="5" HorizontalAlignment="Center" Padding="0" Width="130" Height="50" Click="PedalBtn">
|
||||
<StackPanel Width="130" x:Name="PedalSP">
|
||||
<TextBlock x:Name="pedalStateTxt" Text="AUTO" Foreground="#231F20" FontSize="26.5" FontWeight="Normal" HorizontalAlignment="Center"/>
|
||||
<!-- Underline -->
|
||||
<Rectangle x:Name="pedalUnderLine" Fill="#A4275D" Height="5" Width="90" Margin="0,-3,0,0"/>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
|
||||
|
||||
|
||||
<StackPanel x:Name="PedalAutoContainer" >
|
||||
<!-- Pedal Off Time -->
|
||||
<StackPanel.Styles>
|
||||
<Style Selector="Button:disabled /template/ContentPresenter">
|
||||
<Setter Property="Background" Value="#B3B3B3"/>
|
||||
<Setter Property="Foreground" Value="#A4275D"/>
|
||||
</Style>
|
||||
<Style Selector="Button:pointerover /template/ContentPresenter">
|
||||
<Setter Property="Background" Value="#E6E6E6"></Setter>
|
||||
<Setter Property="Foreground" Value="#A4275D"></Setter>
|
||||
|
||||
</Style>
|
||||
</StackPanel.Styles>
|
||||
|
||||
|
||||
<TextBlock Text="PEDAL OFF TIME" Foreground="Gray" FontSize="15" FontWeight="Normal" HorizontalAlignment="Center"/>
|
||||
<Grid RowDefinitions="*" Margin="5,0">
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto">
|
||||
<Button Classes="PedalOn" Grid.Column="0" Content="−" Background="#E6E6E6" Foreground="#A4275D"
|
||||
Width="35" Height="35" CornerRadius="18" FontSize="16"
|
||||
Click="adjustPedalTime"/>
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<TextBlock x:Name="PedalOnTime" Text="4" FontSize="23.5" FontWeight="Normal" Foreground="Black" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
<TextBlock Text="s" FontSize="23.5" FontWeight="Normal" Foreground="Black" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
|
||||
<Button Classes="PedalOn" Grid.Column="2" Content="+" Background="#E6E6E6" Foreground="#A4275D"
|
||||
Width="35" Height="35" CornerRadius="18" FontSize="16" Click="adjustPedalTime"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<!-- Pedal On Time -->
|
||||
<TextBlock Text="PEDAL ON TIME" Foreground="Gray" FontSize="15" FontWeight="Normal" HorizontalAlignment="Center"/>
|
||||
<Grid RowDefinitions="*" Margin="5,0">
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto">
|
||||
<Button Classes="PedalOff" Grid.Column="0" Content="−" Background="#E6E6E6" Foreground="#A4275D"
|
||||
Width="35" Height="35" CornerRadius="18" FontSize="16" Click="adjustPedalTime"/>
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<TextBlock x:Name="PedalOffTime" Text="4" FontSize="23.5" FontWeight="Normal" Foreground="Black" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
<TextBlock Text=" s" FontSize="23.5" FontWeight="Normal" Foreground="Black" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
|
||||
<Button Classes="PedalOff" Grid.Column="2" Content="+" Background="#E6E6E6" Foreground="#A4275D"
|
||||
Width="35" Height="35" CornerRadius="18" FontSize="16" Click="adjustPedalTime"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Column="1" Height="596" Width="605" IsVisible="True">
|
||||
<Grid.Background >
|
||||
<ImageBrush Source="/Assets/TemperingMachine.png" />
|
||||
</Grid.Background>
|
||||
</Grid>
|
||||
<Grid Grid.Column="2" RowDefinitions="*,12*" HorizontalAlignment="Center" Margin="0,0,15,0">
|
||||
<StackPanel Grid.Row="1" Orientation="Vertical" HorizontalAlignment="Left" >
|
||||
<!--Fountain Temp -->
|
||||
<StackPanel Orientation="Horizontal" >
|
||||
|
||||
<Button IsEnabled="False" Width="150" Height="90" Margin="10" CornerRadius="10" Padding="0">
|
||||
<Button.Styles>
|
||||
<!-- Custom Style for Disabled Button -->
|
||||
<Style Selector="Button:disabled /template/ContentPresenter">
|
||||
<Setter Property="Background" Value="#E6E6E6"/>
|
||||
</Style>
|
||||
</Button.Styles>
|
||||
<StackPanel Spacing="5">
|
||||
<Label FontSize="14.5" FontWeight="Normal" HorizontalContentAlignment="Center" Foreground="#787878" >CHOCOLATE TEMP</Label>
|
||||
<StackPanel
|
||||
Spacing="-10"
|
||||
Orientation="Horizontal"
|
||||
Margin="0,-10,0,0" HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center">
|
||||
<Label x:Name="FountainTempValue" FontSize="35" Foreground="#262223" VerticalAlignment="Center" >-100.0</Label>
|
||||
<Label FontSize="40" Foreground="#262223" VerticalAlignment="Center" >°C</Label>
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
|
||||
</StackPanel>
|
||||
<Button x:Name="fountainBtn" Margin="10" Content="on" Width="150" Height="90" CornerRadius="10">
|
||||
<StackPanel x:Name="FountainSP">
|
||||
<Label FontSize="15" FontWeight="Normal" HorizontalContentAlignment="Center" Foreground="#666666">CHOCOLATE</Label>
|
||||
<Label FontSize="47" FontWeight="Normal" HorizontalContentAlignment="Center" Margin="0,-15,0,0" Foreground="#231F20">ON</Label>
|
||||
<!-- Underline -->
|
||||
<Rectangle Fill="#A4275D" Height="5" Width="110" Margin="0,-15,0,0"></Rectangle>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
|
||||
</Button>
|
||||
|
||||
<!--MOLD HEATER-->
|
||||
<Button x:Name="moldHeaterBtn" Margin="10" Content="on" Width="150" Height="90" CornerRadius="10"
|
||||
Click="toggelOnOffClick">
|
||||
<StackPanel x:Name="MoldHeaterSP">
|
||||
<Label FontSize="15" FontWeight="Normal" HorizontalContentAlignment="Center" Foreground="#666666">MOLD HEATER</Label>
|
||||
<Label FontSize="47" FontWeight="Normal" HorizontalContentAlignment="Center" Margin="0,-15,0,0" Foreground="#231F20">ON</Label>
|
||||
<!-- Underline -->
|
||||
<Rectangle Fill="#A4275D" Height="5" Width="110" Margin="0,-15,0,0"></Rectangle>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
|
||||
</Button>
|
||||
<!--Vibration-->
|
||||
<Button x:Name="vibrationBtn" Margin="10" Content="on" Width="150" Height="90" CornerRadius="10"
|
||||
Click="toggelOnOffClick">
|
||||
<StackPanel x:Name="VibrationSP">
|
||||
<Label FontSize="15" FontWeight="Normal" HorizontalContentAlignment="Center" Foreground="#666666">VIBRATION</Label>
|
||||
<Label FontSize="47" FontWeight="Normal" HorizontalContentAlignment="Center" Margin="0,-15,0,0" Foreground="#231F20">ON</Label>
|
||||
<!-- Underline -->
|
||||
<Rectangle Fill="#A4275D" Height="5" Width="110" Margin="0,-15,0,0"></Rectangle>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
|
||||
</Button>
|
||||
<!--VIBHeater-->
|
||||
<Button x:Name="vibHeaterBtn" Margin="10" Content="on" Width="150" Height="90" CornerRadius="10"
|
||||
Click="toggelOnOffClick">
|
||||
<StackPanel x:Name="VibHeaterSP">
|
||||
<Label FontSize="15" FontWeight="Normal" HorizontalContentAlignment="Center" Foreground="#666666"
|
||||
>VIB. HEATER</Label>
|
||||
<Label FontSize="47" FontWeight="Normal" HorizontalContentAlignment="Center" Margin="0,-15,0,0" Foreground="#231F20">ON</Label>
|
||||
<!-- Underline -->
|
||||
<Rectangle Fill="#A4275D" Height="5" Width="110" Margin="0,-15,0,0"></Rectangle>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Overlay Background for Delet Popup -->
|
||||
<Border x:Name="DeletePopupOverlay" Background="#80000000" Grid.RowSpan="3" IsVisible="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ZIndex="99" PointerPressed="OnIgnorePopupOverlayPointerPressed">
|
||||
<!-- Popup User Control -->
|
||||
|
||||
<!-- Module for Name Entry -->
|
||||
<Grid PointerPressed="" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="20" IsVisible="True">
|
||||
<Border Background="White" CornerRadius="10" Padding="20" BorderThickness="1" ZIndex="101" BorderBrush="#CCC">
|
||||
<StackPanel Spacing="15">
|
||||
<!-- Label for Text Input -->
|
||||
<!-- Label -->
|
||||
|
||||
|
||||
<TextBlock Text="Exit Warning!!"
|
||||
FontSize="20"
|
||||
FontWeight="Bold"
|
||||
Foreground="Red"
|
||||
Margin="0,0,0,8" />
|
||||
<StackPanel>
|
||||
<TextBlock x:Name="deleteMsg" Text="Are you sure?"
|
||||
FontSize="16"
|
||||
FontWeight="Bold"
|
||||
Foreground="#333"
|
||||
Margin="0,0,0,8" />
|
||||
</StackPanel>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Button Panel -->
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Spacing="10">
|
||||
<!-- yes Button -->
|
||||
<Button
|
||||
Content="Yes"
|
||||
FontSize="16"
|
||||
Padding="10,5"
|
||||
Click="YesBtnClick"
|
||||
Foreground="White" >
|
||||
<Button.Background>
|
||||
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
|
||||
<GradientStop Color="#A4275D" Offset="0" />
|
||||
<GradientStop Color="#A4275D" Offset="1" />
|
||||
</LinearGradientBrush>
|
||||
</Button.Background>
|
||||
<Button.Styles>
|
||||
<Style Selector="Button.SpecialButtonStyle:pointerover /template/ContentPresenter">
|
||||
<Setter Property="Background" Value="#A4275D"/>
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
</Style>
|
||||
</Button.Styles>
|
||||
|
||||
</Button>
|
||||
<!-- No Button -->
|
||||
<Button
|
||||
Content="No"
|
||||
FontSize="16"
|
||||
Padding="10,5"
|
||||
Background="Gray"
|
||||
Foreground="White"
|
||||
Click="OnIgnorePopupOverlayPointerPressed">
|
||||
<Button.Styles>
|
||||
<Style Selector="Button.SpecialButtonStyle:pointerover /template/ContentPresenter">
|
||||
<Setter Property="Background" Value="Gray"/>
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
</Style>
|
||||
</Button.Styles>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- Overlay Background for Delet Popup -->
|
||||
<Border x:Name="tempErrorPopupOverlay" Background="#80000000" Grid.RowSpan="3" IsVisible="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ZIndex="99" PointerPressed="">
|
||||
<!-- Popup User Control -->
|
||||
|
||||
<!-- Module for Name Entry -->
|
||||
<Grid PointerPressed="" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="20" IsVisible="True">
|
||||
<Border Background="White" CornerRadius="10" Padding="20" BorderThickness="1" ZIndex="101" BorderBrush="#CCC">
|
||||
<StackPanel Spacing="15">
|
||||
<!-- Label for Text Input -->
|
||||
<!-- Label -->
|
||||
|
||||
|
||||
<TextBlock Text="Temperature Error!!"
|
||||
FontSize="20"
|
||||
FontWeight="Bold"
|
||||
Foreground="Red"
|
||||
Margin="0,0,0,8" />
|
||||
<StackPanel>
|
||||
<TextBlock x:Name="tempErrorMsg" Text="Error locating temperature do you want to stop?"
|
||||
FontSize="16"
|
||||
FontWeight="Bold"
|
||||
Foreground="#333"
|
||||
Margin="0,0,0,8" />
|
||||
</StackPanel>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Button Panel -->
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Spacing="10">
|
||||
<!-- yes Button -->
|
||||
<Button
|
||||
Content="Yes"
|
||||
FontSize="16"
|
||||
Padding="10,5"
|
||||
Click="ErrorYesBtnClick"
|
||||
Foreground="White" >
|
||||
<Button.Background>
|
||||
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
|
||||
<GradientStop Color="#A4275D" Offset="0" />
|
||||
<GradientStop Color="#A4275D" Offset="1" />
|
||||
</LinearGradientBrush>
|
||||
</Button.Background>
|
||||
<Button.Styles>
|
||||
<Style Selector="Button.SpecialButtonStyle:pointerover /template/ContentPresenter">
|
||||
<Setter Property="Background" Value="#A4275D"/>
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
</Style>
|
||||
</Button.Styles>
|
||||
|
||||
</Button>
|
||||
<!-- No Button -->
|
||||
<Button
|
||||
Content="No"
|
||||
FontSize="16"
|
||||
Padding="10,5"
|
||||
Background="Gray"
|
||||
Foreground="White"
|
||||
Click="HideTempErrorPopUp">
|
||||
<Button.Styles>
|
||||
<Style Selector="Button.SpecialButtonStyle:pointerover /template/ContentPresenter">
|
||||
<Setter Property="Background" Value="Gray"/>
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
</Style>
|
||||
</Button.Styles>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
||||
388
DaireApplication/Views/UserController/Settings.axaml.cs
Normal file
@@ -0,0 +1,388 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Documents;
|
||||
using Avalonia.Controls.Shapes;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.Media;
|
||||
using AvaloniaApplication1.DataBase;
|
||||
using DaireApplication.DataBase;
|
||||
using DaireApplication.ViewModels;
|
||||
using DaireApplication.Views;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Reflection.PortableExecutable;
|
||||
using System.Threading;
|
||||
|
||||
namespace DaireApplication;
|
||||
|
||||
public partial class Settings : UserControl
|
||||
{
|
||||
Button controllButton = new Button();
|
||||
private MainWindow? _mainWindow;
|
||||
private UserTable? _currentUser;
|
||||
public RecipeTable? _recipeTable;
|
||||
private MachineTable _machine;
|
||||
public string ActiveColor { get; set; } = "#A4275D";
|
||||
public string PassiveColor { get; set; } = "#666666";
|
||||
|
||||
public Settings()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
public Settings(MainWindow mainWindow, UserTable currentUser,RecipeTable recipeTable)
|
||||
{
|
||||
_currentUser = currentUser;
|
||||
_mainWindow = mainWindow;
|
||||
_recipeTable = recipeTable;
|
||||
_machine = new MachineTable();
|
||||
_machine = _machine.ReadMachine();
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
setDefaultSettings();
|
||||
|
||||
setDafaultValues();
|
||||
mixerBtn.Click += _mainWindow.MotorClick;
|
||||
fountainBtn.Click += _mainWindow.FountainClick;
|
||||
}
|
||||
|
||||
|
||||
private void toggelOnOffClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Button button)
|
||||
{
|
||||
var StackPanel = button.Content as StackPanel;
|
||||
var Label = StackPanel.Children;
|
||||
var underLine = Label[2] as Avalonia.Controls.Shapes.Rectangle;
|
||||
var titelLable = Label[0] as Label;
|
||||
|
||||
|
||||
|
||||
if (Label[1] is Label targetLable)
|
||||
{
|
||||
if (targetLable.Content == "ON")
|
||||
{
|
||||
if (titelLable.Content == "MOLD HEATER")
|
||||
{
|
||||
_mainWindow.moldHeaterMotor = 0;
|
||||
}
|
||||
if (titelLable.Content == "VIBRATION")
|
||||
{
|
||||
_mainWindow.vibrationMotor = 0;
|
||||
|
||||
}
|
||||
if (titelLable.Content == "VIB. HEATER")
|
||||
{
|
||||
_mainWindow.vibHeaterMotor = 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (titelLable.Content == "MOLD HEATER")
|
||||
{
|
||||
_mainWindow.moldHeaterMotor = 1;
|
||||
}
|
||||
if (titelLable.Content == "VIBRATION")
|
||||
{
|
||||
_mainWindow.vibrationMotor = 1;
|
||||
|
||||
}
|
||||
if (titelLable.Content == "VIB. HEATER")
|
||||
{
|
||||
_mainWindow.vibHeaterMotor = 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
private void PedalBtn(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Button button)
|
||||
{
|
||||
var StackPanel = button.Content as StackPanel;
|
||||
var Label = StackPanel.Children;
|
||||
var underLine = Label[1] as Avalonia.Controls.Shapes.Rectangle;
|
||||
if (Label[0] is TextBlock targetLable)
|
||||
{
|
||||
if (targetLable.Text == "AUTO")
|
||||
{
|
||||
if (_mainWindow.pedalOnTimer!=null )
|
||||
{
|
||||
_mainWindow.pedalOnTimer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
_mainWindow.pedalOnTimer = null;
|
||||
_mainWindow.pedalOnSeconds = 0;
|
||||
}
|
||||
if (_mainWindow.pedalOffTimer!=null)
|
||||
{
|
||||
_mainWindow.pedalOffTimer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
_mainWindow.pedalOffTimer = null;
|
||||
_mainWindow.pedalOffSeconds = 0;
|
||||
}
|
||||
_mainWindow.pedalMotor = 0;
|
||||
targetLable.Text = "MANUAL";
|
||||
underLine.Fill = Brush.Parse("#666666");
|
||||
PedalAutoContainer.IsEnabled = false;
|
||||
_recipeTable.Pedal = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_mainWindow.pedalMotor = 1;
|
||||
_mainWindow.pedalState = -1;
|
||||
_mainWindow.setPedalTimerOnce = 1;
|
||||
_mainWindow.pedalOnSeconds = 0;
|
||||
_mainWindow.pedalOffSeconds = 0;
|
||||
targetLable.Text = "AUTO";
|
||||
underLine.Fill = Brush.Parse("#A4275D");
|
||||
PedalAutoContainer.IsEnabled = true;
|
||||
_recipeTable.Pedal = false;
|
||||
|
||||
}
|
||||
_recipeTable.UpdateRecipe(_recipeTable);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
private void adjustPedalTime(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Button button)
|
||||
{
|
||||
if (button.Classes[0].ToString()== "PedalOff")
|
||||
{
|
||||
if (button.Content == "−")
|
||||
{
|
||||
if (Int32.Parse(PedalOffTime.Text) > 0)
|
||||
{
|
||||
PedalOffTime.Text = (Int32.Parse(PedalOffTime.Text) - 1).ToString();
|
||||
}
|
||||
|
||||
}
|
||||
else if (button.Content == "+")
|
||||
{
|
||||
|
||||
PedalOffTime.Text = (Int32.Parse(PedalOffTime.Text) + 1).ToString();
|
||||
}
|
||||
_recipeTable.PedalOffTime = Int32.Parse(PedalOffTime.Text);
|
||||
_recipeTable.UpdateRecipe(_recipeTable);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (button.Content == "−")
|
||||
{
|
||||
if (Int32.Parse(PedalOnTime.Text) > 0)
|
||||
{
|
||||
PedalOnTime.Text = (Int32.Parse(PedalOnTime.Text) - 1).ToString();
|
||||
}
|
||||
|
||||
}
|
||||
else if (button.Content == "+")
|
||||
{
|
||||
if (int.TryParse(PedalOnTime.Text, out int value))
|
||||
{
|
||||
if (value < 9)
|
||||
{
|
||||
PedalOnTime.Text = (value + 1).ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
_recipeTable.PedalOnTime = Int32.Parse(PedalOnTime.Text);
|
||||
_recipeTable.UpdateRecipe(_recipeTable);
|
||||
}
|
||||
_recipeTable = _recipeTable.ReadRecipesById(_recipeTable.Id.ToString());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private async void OnIgnorePopupOverlayPointerPressed(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
DeletePopupOverlay.IsVisible = false;
|
||||
|
||||
|
||||
|
||||
}
|
||||
private async void HideTempErrorPopUp(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
_mainWindow.pauseTimer = false;
|
||||
_mainWindow.pauseTempTracking = false; // Allow process to continue after clicking "No"
|
||||
_mainWindow.tempWarningAccepted = true; // User accepted the temperature warning
|
||||
tempErrorPopupOverlay.IsVisible = false;
|
||||
}
|
||||
private async void YesBtnClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Button button)
|
||||
{
|
||||
if (DeletePopupOverlay.Tag=="home")
|
||||
{
|
||||
|
||||
_mainWindow.resetAll();
|
||||
// rest the board
|
||||
_mainWindow.restBoard = true;
|
||||
_mainWindow.UserName.Content = "Select User";
|
||||
_mainWindow.footerMsg.Text = "";
|
||||
_mainWindow.ContentArea.Content = new Home(_mainWindow);
|
||||
}
|
||||
else if (DeletePopupOverlay.Tag == "recipeSel")
|
||||
{
|
||||
_mainWindow.resetAll();
|
||||
// rest the board
|
||||
_mainWindow.restBoard = true;
|
||||
_mainWindow.footerMsg.Text = "";
|
||||
_mainWindow.ContentArea.Content = new Recipe(_mainWindow, Program.currentUser);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
private async void ErrorYesBtnClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Button button)
|
||||
{
|
||||
//_mainWindow.pause = true;
|
||||
//_mainWindow.pauseTempTracking = true;
|
||||
//_mainWindow.pauseTimer = true;
|
||||
|
||||
// stop the recipe
|
||||
_mainWindow.startRecipe = 0;
|
||||
_mainWindow.Heating = 0;
|
||||
_mainWindow.cooling = 0;
|
||||
_mainWindow.pouring = 0;
|
||||
_mainWindow.PumbOn = -1;
|
||||
_mainWindow.pedalMotor = -1;
|
||||
if (_mainWindow.heatingTimer != null)
|
||||
{
|
||||
_mainWindow.heatingTimer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
_mainWindow.heatingSeconds = 0;
|
||||
}
|
||||
if (_mainWindow.coolingTimer != null)
|
||||
{
|
||||
_mainWindow.coolingTimer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
_mainWindow.coolingSeconds = 0;
|
||||
}
|
||||
if (_mainWindow.pouringTimer != null)
|
||||
{
|
||||
_mainWindow.pouringTimer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
_mainWindow.pouringSeconds = 0;
|
||||
}
|
||||
var fount = _mainWindow._mapping.Find(x => x.Name.ToLower() == "Pump".ToLower());
|
||||
if (fount != null)
|
||||
{
|
||||
if (fount.BitNumbers.Count > 0)
|
||||
{
|
||||
foreach (var bit in fount.BitNumbers)
|
||||
{
|
||||
|
||||
_mainWindow.holdingRegister.motor &= (ushort)~(1 << bit);
|
||||
}
|
||||
}
|
||||
}
|
||||
_mainWindow.holdingRegister.setTemp1 = -10000;
|
||||
_mainWindow.holdingRegister.setTemp2 = -10000;
|
||||
_mainWindow.holdingRegister.setTemp3 = -10000;
|
||||
_mainWindow.holdingRegister.setTemp4 = -10000;
|
||||
await _mainWindow.WriteToSerialAsync("ErrorYesBtnClick");
|
||||
tempErrorPopupOverlay.IsVisible = false;
|
||||
_mainWindow.footerMsg.Text = "Recipe Stoped";
|
||||
_mainWindow.recipeStartBtn.Content = "START RECIPE";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void setDefaultSettings()
|
||||
{
|
||||
//Set Track Up
|
||||
_mainWindow.HomeTrack.IsVisible = true;
|
||||
//_mainWindow.HomePolygon.Stroke = Avalonia.Media.Brushes.Black;
|
||||
_mainWindow.RecipeSelTrack.IsVisible = true;
|
||||
_mainWindow.RecipeSelPolygon.Stroke = Avalonia.Media.Brushes.Black;
|
||||
_mainWindow.RunInterfaceTrack.IsVisible = true;
|
||||
_mainWindow.RunInterfacePolygon.Stroke = Brush.Parse("#A4275D");
|
||||
_mainWindow.RecipePanelTrack.IsVisible = false;
|
||||
_mainWindow.RecipeEditTrack.IsVisible = false;
|
||||
_mainWindow.SettingTrack.IsVisible = false;
|
||||
_mainWindow.DiagnosticsTrack.IsVisible = false;
|
||||
_mainWindow.TitleBtn.IsVisible = true;
|
||||
_mainWindow.Title.Text = _recipeTable.Name;
|
||||
|
||||
//Set Footer
|
||||
_mainWindow.footerMsg.Text = "Ready";
|
||||
_mainWindow.footerMsg.MaxWidth = 500;
|
||||
_mainWindow.footer.Background = Avalonia.Media.Brushes.WhiteSmoke;
|
||||
_mainWindow.footerMsg.Foreground = Avalonia.Media.Brushes.Green;
|
||||
_mainWindow.footerDate.Text = DateTime.Now.ToString("dd/MM/yyyy");
|
||||
_mainWindow.footerTime.Text = DateTime.Now.ToString("hh:mm tt");
|
||||
_mainWindow.footerDateContainer.IsVisible = true;
|
||||
_mainWindow.footerStartBtn.IsVisible = true;
|
||||
_mainWindow.adminBtns.IsVisible = false;
|
||||
}
|
||||
private void setDafaultValues()
|
||||
{
|
||||
//Recipe Settings
|
||||
heatingValue.Content = _recipeTable.HeatingGoal;
|
||||
coolingValue.Content = _recipeTable.CoolingGoal;
|
||||
pouringValue.Content = _recipeTable.PouringGoal;
|
||||
//tankTemp
|
||||
TankTempValue.Content = _recipeTable?.TankTemp;
|
||||
//mixer
|
||||
var mixerChildren= MixerSP.Children;
|
||||
var mixerLable = mixerChildren[1] as Label;
|
||||
mixerLable.Content = _recipeTable.Mixer.Value ? "ON" : "OFF";
|
||||
var mixerUnderLine = mixerChildren[2] as Avalonia.Controls.Shapes.Rectangle;
|
||||
mixerUnderLine.Fill = _recipeTable.Mixer.Value ? Brush.Parse(ActiveColor) : Brush.Parse(PassiveColor);
|
||||
//pedal
|
||||
var pedalChildren = PedalSP.Children;
|
||||
var pedalText = pedalChildren[0] as TextBlock;
|
||||
var pedalUnderLine = pedalChildren[1] as Avalonia.Controls.Shapes.Rectangle;
|
||||
if (_recipeTable.Pedal.Value)
|
||||
{
|
||||
pedalText.Text = "MANUAL";
|
||||
pedalUnderLine.Fill = Brush.Parse(PassiveColor);
|
||||
PedalAutoContainer.IsEnabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
pedalText.Text = "AUTO";
|
||||
pedalUnderLine.Fill = Brush.Parse(ActiveColor);
|
||||
PedalAutoContainer.IsEnabled = true;
|
||||
}
|
||||
PedalOffTime.Text = _recipeTable.PedalOffTime.ToString();
|
||||
PedalOnTime.Text = _recipeTable.PedalOnTime.ToString();
|
||||
//fountain Temp
|
||||
FountainTempValue.Content = _recipeTable?.FountainTemp;
|
||||
//fountain
|
||||
var fountainChildren = FountainSP.Children;
|
||||
var fountainLable = fountainChildren[1] as Label;
|
||||
fountainLable.Content = _recipeTable.Fountain.Value ? "ON" : "OFF";
|
||||
var fountainUnderLine = fountainChildren[2] as Avalonia.Controls.Shapes.Rectangle;
|
||||
fountainUnderLine.Fill = _recipeTable.Fountain.Value ? Brush.Parse(ActiveColor) : Brush.Parse(PassiveColor);
|
||||
//mold Heater
|
||||
var moldHeaterChildren = MoldHeaterSP.Children;
|
||||
var moldHeaterLable = moldHeaterChildren[1] as Label;
|
||||
moldHeaterLable.Content = _recipeTable.MoldHeater.Value ? "ON" : "OFF";
|
||||
var moldHeaterUnderLine = moldHeaterChildren[2] as Avalonia.Controls.Shapes.Rectangle;
|
||||
moldHeaterUnderLine.Fill = _recipeTable.MoldHeater.Value ? Brush.Parse(ActiveColor) : Brush.Parse(PassiveColor);
|
||||
// vibration
|
||||
var vibrationChildren = VibrationSP.Children;
|
||||
var vibrationLable = vibrationChildren[1] as Label;
|
||||
vibrationLable.Content = _recipeTable.Vibration.Value ? "ON" : "OFF";
|
||||
var vibrationUnderLine = vibrationChildren[2] as Avalonia.Controls.Shapes.Rectangle;
|
||||
vibrationUnderLine.Fill = _recipeTable.Vibration.Value ? Brush.Parse(ActiveColor) : Brush.Parse(PassiveColor);
|
||||
// vib heater
|
||||
var vibHeaterChildren = VibHeaterSP.Children;
|
||||
var vibHeaterLable = vibHeaterChildren[1] as Label;
|
||||
vibHeaterLable.Content = _recipeTable.VibHeater.Value ? "ON" : "OFF";
|
||||
var vibHeaterUnderLine = vibHeaterChildren[2] as Avalonia.Controls.Shapes.Rectangle;
|
||||
vibHeaterUnderLine.Fill = _recipeTable.VibHeater.Value ? Brush.Parse(ActiveColor) : Brush.Parse(PassiveColor);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
783
DaireApplication/Views/UserController/Software.axaml
Normal file
@@ -0,0 +1,783 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:DaireApplication"
|
||||
x:DataType="local:Software"
|
||||
Width="1280" Height="620" Background="#b3b3b3"
|
||||
x:Class="DaireApplication.Software"
|
||||
>
|
||||
<UserControl.Styles>
|
||||
<Style Selector="ComboBox.noArrow">
|
||||
<Setter Property="Template">
|
||||
<ControlTemplate TargetType="ComboBox">
|
||||
<Grid>
|
||||
<ToggleButton x:Name="PART_Button"
|
||||
Focusable="False"
|
||||
ClickMode="Press"
|
||||
IsChecked="{Binding IsDropDownOpen,
|
||||
RelativeSource={RelativeSource TemplatedParent},
|
||||
Mode=TwoWay}"
|
||||
Background="#E6E6E6"
|
||||
Width="210" Height="40">
|
||||
<Border Background="#E6E6E6"
|
||||
CornerRadius="8"
|
||||
Padding="0,0">
|
||||
<ContentPresenter x:Name="PART_SelectionBoxPresenter"
|
||||
Content="{TemplateBinding SelectionBoxItem}"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="20"
|
||||
Foreground="#af196f"/>
|
||||
</Border>
|
||||
</ToggleButton>
|
||||
|
||||
<Popup x:Name="PART_Popup"
|
||||
PlacementTarget="{Binding #PART_Button}"
|
||||
Placement="Bottom"
|
||||
IsOpen="{Binding IsDropDownOpen,
|
||||
RelativeSource={RelativeSource TemplatedParent},
|
||||
Mode=TwoWay}">
|
||||
<Border Background="White"
|
||||
BorderBrush="Gray"
|
||||
BorderThickness="1">
|
||||
<ScrollViewer>
|
||||
<ItemsPresenter />
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
</Popup>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style Selector="TextBlock.lbl">
|
||||
<Setter Property="Foreground" Value="#000000"/>
|
||||
</Style>
|
||||
<Style Selector="ComboBoxItem">
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
</Style>
|
||||
|
||||
<Style Selector="ComboBoxItem:selectable:checked">
|
||||
<Setter Property="Foreground" Value="#af196f"/>
|
||||
</Style>
|
||||
|
||||
<Style Selector="ComboBoxItem:pointerover">
|
||||
<Setter Property="Foreground" Value="#af196f"/>
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
</Style>
|
||||
|
||||
</UserControl.Styles>
|
||||
|
||||
|
||||
<Grid RowDefinitions="*">
|
||||
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,*">
|
||||
|
||||
|
||||
<Border Grid.Column="0" Padding="10">
|
||||
|
||||
|
||||
<StackPanel Spacing="8">
|
||||
|
||||
|
||||
<!--box-->
|
||||
<Border Width="222" Height="224" Background="#f9f9f9" CornerRadius="10" Padding="10" ZIndex="100" >
|
||||
<StackPanel Spacing="5">
|
||||
<TextBlock
|
||||
Foreground="#918f90"
|
||||
FontSize="20.5" HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center">PASSWORDS RESET</TextBlock>
|
||||
<!--row-->
|
||||
<Border Width="210" Height="40" Background="#e6e6e6" CornerRadius="5">
|
||||
<Button Background="Transparent"
|
||||
Width="210"
|
||||
Click="showChangePasswordPopUp">
|
||||
<TextBlock
|
||||
Foreground="#231f20"
|
||||
FontSize="20.5"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center" Classes="user">
|
||||
ADMINISTRATOR
|
||||
</TextBlock>
|
||||
</Button>
|
||||
|
||||
</Border>
|
||||
<!--row-->
|
||||
<Border Width="210" Height="40" Background="#e6e6e6" CornerRadius="5">
|
||||
<Button Background="Transparent" Width="210"
|
||||
Click="showChangePasswordPopUp">
|
||||
<TextBlock Classes="user"
|
||||
Foreground="#231f20"
|
||||
FontSize="20.5"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center">
|
||||
CHEF
|
||||
</TextBlock>
|
||||
</Button>
|
||||
|
||||
</Border>
|
||||
<!--row-->
|
||||
<Border Width="210" Height="40" Background="#e6e6e6" CornerRadius="5">
|
||||
<Button Background="Transparent" Width="210" Click="showChangePasswordPopUp">
|
||||
<TextBlock
|
||||
Foreground="#231f20"
|
||||
FontSize="20.5"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center" Classes="user">
|
||||
OPERATOR1
|
||||
</TextBlock>
|
||||
</Button>
|
||||
|
||||
</Border>
|
||||
<!--row-->
|
||||
<Border Width="210" Height="40" Background="#e6e6e6" CornerRadius="5">
|
||||
<Button Background="Transparent" Width="210" Click="showChangePasswordPopUp">
|
||||
<TextBlock
|
||||
Foreground="#231f20"
|
||||
FontSize="20.5"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center" Classes="user">
|
||||
OPERATOR2
|
||||
</TextBlock>
|
||||
</Button>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<!--box1 -->
|
||||
|
||||
<Border Width="222" Height="178" Background="#f9f9f9" CornerRadius="10" Padding="10" ZIndex="100">
|
||||
<StackPanel Spacing="5">
|
||||
<TextBlock
|
||||
Foreground="#918f90"
|
||||
FontSize="20.5"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center">SCREEN SETTINGS</TextBlock>
|
||||
<!--row-->
|
||||
<Border Width="210" Height="40" Background="#e6e6e6" CornerRadius="5" >
|
||||
<Button Background="Transparent"
|
||||
Width="210" Height="40" Click="showScreenPopUp" Tag="BRIGHTNESS" >
|
||||
<Grid RowDefinitions="*">
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,*">
|
||||
<TextBlock
|
||||
Foreground="#231f20"
|
||||
FontSize="20.5"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center" Grid.Column="0">
|
||||
BRIGHTNESS
|
||||
</TextBlock>
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal"
|
||||
HorizontalAlignment="Right">
|
||||
<TextBlock
|
||||
Foreground="#af196f"
|
||||
FontSize="20.5"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center"
|
||||
x:Name="brightnessValue"
|
||||
>
|
||||
80
|
||||
</TextBlock>
|
||||
<TextBlock
|
||||
Foreground="#af196f"
|
||||
FontSize="20.5"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center">
|
||||
%
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
</Button>
|
||||
|
||||
|
||||
</Border>
|
||||
<!--row-->
|
||||
<Border Width="210" Height="40" Background="#e6e6e6" CornerRadius="5" >
|
||||
<Button Background="Transparent"
|
||||
Width="210"
|
||||
Height="40" Click="showScreenPopUp" Tag="AUTO DIM">
|
||||
<Grid RowDefinitions="*">
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,*">
|
||||
<TextBlock
|
||||
Foreground="#231f20"
|
||||
FontSize="20.5"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center" Grid.Column="0">
|
||||
AUTO DIM
|
||||
</TextBlock>
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal"
|
||||
Spacing="5" HorizontalAlignment="Right">
|
||||
<TextBlock
|
||||
Foreground="#af196f"
|
||||
FontSize="20.5"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center"
|
||||
x:Name="dimValue"
|
||||
>
|
||||
60
|
||||
</TextBlock>
|
||||
<TextBlock
|
||||
Foreground="#af196f"
|
||||
FontSize="20.5"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center">
|
||||
Min
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
</Button>
|
||||
|
||||
|
||||
</Border>
|
||||
<!--row-->
|
||||
<Border Width="210" Height="40" Background="#e6e6e6" CornerRadius="5" >
|
||||
<Button Background="Transparent"
|
||||
Width="210"
|
||||
Height="40" Click="showScreenPopUp" Tag="AUTO OFF">
|
||||
<Grid RowDefinitions="*">
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,*">
|
||||
<TextBlock
|
||||
Foreground="#231f20"
|
||||
FontSize="20.5"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center" Grid.Column="0">
|
||||
AUTO OFF
|
||||
</TextBlock>
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal"
|
||||
Spacing="5" HorizontalAlignment="Right">
|
||||
<TextBlock
|
||||
Foreground="#af196f"
|
||||
FontSize="20.5"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center"
|
||||
x:Name="offValue"
|
||||
>
|
||||
90
|
||||
</TextBlock>
|
||||
<TextBlock
|
||||
Foreground="#af196f"
|
||||
FontSize="20.5"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center">
|
||||
Min
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
</Button>
|
||||
|
||||
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!--box-->
|
||||
|
||||
<Border Width="222" Height="178" Background="#f9f9f9" CornerRadius="10" Padding="10" >
|
||||
<StackPanel Spacing="5">
|
||||
<TextBlock
|
||||
Foreground="#918f90"
|
||||
FontSize="20.5"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center">COM SETTINGS</TextBlock>
|
||||
<!--row-->
|
||||
<Border Width="210" Height="40" Background="#e6e6e6" CornerRadius="5" Padding="0" >
|
||||
<Grid RowDefinitions="*">
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,*">
|
||||
<ComboBox x:Name="portComboBox"
|
||||
Margin="0"
|
||||
Classes="noArrow"
|
||||
SelectedIndex="0"
|
||||
SelectedItem="{Binding SelectedPort}"
|
||||
ItemsSource="{Binding SerialPorts, Mode=OneWay}"
|
||||
SelectionChanged="portChanged" >
|
||||
</ComboBox>
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal"
|
||||
HorizontalAlignment="Right">
|
||||
|
||||
</StackPanel>
|
||||
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
|
||||
</Border>
|
||||
<!--row-->
|
||||
<Border Width="210" Height="40" Background="#e6e6e6" CornerRadius="5" Padding="0" >
|
||||
<Button Background="Transparent"
|
||||
Width="210"
|
||||
Click="showComPopUp">
|
||||
<TextBlock
|
||||
Foreground="#231f20"
|
||||
FontSize="20.5"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center" >
|
||||
COM Settings
|
||||
</TextBlock>
|
||||
</Button>
|
||||
</Border>
|
||||
<!--row-->
|
||||
<Border Width="210" Height="40" Background="#e6e6e6" CornerRadius="5" Padding="0" >
|
||||
<Button Background="Transparent"
|
||||
Width="210"
|
||||
Click="ShowTempPopUp">
|
||||
<TextBlock
|
||||
Foreground="#231f20"
|
||||
FontSize="18.5"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center" >
|
||||
Temperature Settings
|
||||
</TextBlock>
|
||||
</Button>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
|
||||
|
||||
</Border>
|
||||
<Grid Grid.Column="1"></Grid>
|
||||
</Grid>
|
||||
|
||||
|
||||
<!-- Overlay Background for Add Popup -->
|
||||
<Border x:Name="passwordPopupOverlay" Background="#80000000" Grid.RowSpan="3" IsVisible="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ZIndex="99" PointerPressed="hidePasswordPopUp">
|
||||
<!-- Popup User Control -->
|
||||
|
||||
<!-- Module for Name Entry -->
|
||||
<Grid x:Name="NameModule" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="20" IsVisible="True" PointerPressed="InnerPopupPointerPressed">
|
||||
<Border Background="White" CornerRadius="10" Padding="20" BorderThickness="1" ZIndex="101" BorderBrush="#CCC">
|
||||
<StackPanel Spacing="15">
|
||||
<!-- Label for Text Input -->
|
||||
<!-- Label -->
|
||||
|
||||
|
||||
<TextBlock x:Name="titelMsg" Text="New Addministrator Password:"
|
||||
FontSize="18"
|
||||
FontWeight="Bold"
|
||||
Foreground="#333"
|
||||
Margin="0,0,0,8" />
|
||||
|
||||
<Border Name="passwordBorder">
|
||||
<TextBox x:Name="passwordInput"
|
||||
Width="300"
|
||||
Height="30"
|
||||
BorderBrush="#CCC"
|
||||
BorderThickness="1"
|
||||
MaxLength="9"
|
||||
Tag="password"
|
||||
|
||||
></TextBox>
|
||||
|
||||
</Border>
|
||||
|
||||
<!-- Local styles for this specific TextBox -->
|
||||
|
||||
<CheckBox x:Name="isActivePass" Content="Enable/Disable" Foreground="Black">
|
||||
<CheckBox.Styles>
|
||||
<Style Selector="CheckBox">
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
<Setter Property="Background" Value="White"/>
|
||||
<Setter Property="BorderBrush" Value="Black"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="Padding" Value="5"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
</Style>
|
||||
|
||||
<Style Selector="CheckBox:checked">
|
||||
<Setter Property="Foreground" Value="Teal"/>
|
||||
</Style>
|
||||
</CheckBox.Styles>
|
||||
</CheckBox>
|
||||
<!-- Button Panel -->
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Spacing="10">
|
||||
<!-- Save Button -->
|
||||
<Button x:Name="SaveButton"
|
||||
Content="OK"
|
||||
FontSize="16"
|
||||
Padding="10,5"
|
||||
Click="passwordSaveClick"
|
||||
Foreground="White" >
|
||||
<Button.Background>
|
||||
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
|
||||
<GradientStop Color="#A4275D" Offset="0" />
|
||||
<GradientStop Color="#A4275D" Offset="1" />
|
||||
</LinearGradientBrush>
|
||||
</Button.Background>
|
||||
<Button.Effect>
|
||||
|
||||
</Button.Effect>
|
||||
</Button>
|
||||
<!-- Cancel Button -->
|
||||
<Button x:Name="CancelButton"
|
||||
Content="Cancel"
|
||||
FontSize="16"
|
||||
Padding="10,5"
|
||||
Background="Gray"
|
||||
Foreground="White"
|
||||
Click="hidePasswordPopUp"
|
||||
|
||||
>
|
||||
<Button.Effect>
|
||||
|
||||
</Button.Effect>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- Overlay Background for Add Popup -->
|
||||
<Border x:Name="secreenPopupOverlay" Background="#80000000" Grid.RowSpan="3" IsVisible="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" PointerPressed="hideScreenPopUp">
|
||||
<!-- Popup User Control -->
|
||||
|
||||
<!-- Module for Name Entry -->
|
||||
<Grid PointerPressed="InnerPopupPointerPressed" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="20" IsVisible="True">
|
||||
<Border Background="White" CornerRadius="10" Padding="20" BorderThickness="1" ZIndex="101" BorderBrush="#CCC" >
|
||||
<StackPanel Spacing="15">
|
||||
<!-- Label for Text Input -->
|
||||
<!-- Label -->
|
||||
|
||||
|
||||
<TextBlock x:Name="titelSecreenMsg" Text="Enter Brightness percentage:"
|
||||
FontSize="18"
|
||||
FontWeight="Bold"
|
||||
Foreground="#333"
|
||||
Margin="0,0,0,8" />
|
||||
|
||||
|
||||
<TextBlock x:Name="sliderValue" Margin="0,10,0,0" Foreground="Black">0</TextBlock>
|
||||
<Slider x:Name="slider" Minimum="0" Maximum="120"
|
||||
TickFrequency="1"
|
||||
IsSnapToTickEnabled="True"
|
||||
Background="Black"
|
||||
ValueChanged="OnSliderValueChanged"/>
|
||||
|
||||
<!-- Button Panel -->
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Spacing="10">
|
||||
<!-- Save Button -->
|
||||
<Button x:Name="secreenSaveButton"
|
||||
Content="OK"
|
||||
FontSize="16"
|
||||
Padding="10,5"
|
||||
Click="screenSaveClick"
|
||||
Foreground="White" >
|
||||
<Button.Background>
|
||||
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
|
||||
<GradientStop Color="#A4275D" Offset="0" />
|
||||
<GradientStop Color="#A4275D" Offset="1" />
|
||||
</LinearGradientBrush>
|
||||
</Button.Background>
|
||||
<Button.Effect>
|
||||
|
||||
</Button.Effect>
|
||||
</Button>
|
||||
<!-- Cancel Button -->
|
||||
<Button x:Name="CancelScreenButton"
|
||||
Content="Cancel"
|
||||
FontSize="16"
|
||||
Padding="10,5"
|
||||
Background="Gray"
|
||||
Foreground="White"
|
||||
Click="hideScreenPopUp"
|
||||
|
||||
>
|
||||
<Button.Effect>
|
||||
|
||||
</Button.Effect>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
<!-- Overlay Background for Com Settings Popup -->
|
||||
<Border x:Name="comPopupOverlay" Background="#80000000" Grid.RowSpan="3" IsVisible="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" PointerPressed="hideComPopUp">
|
||||
<!-- Popup User Control -->
|
||||
|
||||
<!-- Module for Name Entry -->
|
||||
<Grid PointerPressed="InnerPopupPointerPressed" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="20" IsVisible="True">
|
||||
<Border Background="White" CornerRadius="10" Padding="20" BorderThickness="1" ZIndex="101" BorderBrush="#CCC" >
|
||||
<StackPanel Spacing="15">
|
||||
<!-- Label for Text Input -->
|
||||
<!-- Label -->
|
||||
|
||||
<TextBlock Text="Com Settings"
|
||||
FontSize="18"
|
||||
FontWeight="Bold"
|
||||
Foreground="#333"
|
||||
Margin="0,0,0,8" />
|
||||
<StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Margin="0,0,5,0" Foreground="Black">Bound Rate:</TextBlock>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
<ComboBox
|
||||
x:Name="boundRateComboBox"
|
||||
|
||||
Margin="0"
|
||||
HorizontalAlignment="Center"
|
||||
Classes="noArrow"
|
||||
SelectedIndex="0"
|
||||
>
|
||||
<ComboBoxItem Tag="0" Content="9600"/>
|
||||
<ComboBoxItem Tag="1" Content="14400"/>
|
||||
<ComboBoxItem Tag="2" Content="19200"/>
|
||||
<ComboBoxItem Tag="3" Content="28800"/>
|
||||
<ComboBoxItem Tag="4" Content="38400"/>
|
||||
<ComboBoxItem Tag="5" Content="57600"/>
|
||||
<ComboBoxItem Tag="6" Content="115200"/>
|
||||
</ComboBox>
|
||||
|
||||
|
||||
|
||||
</StackPanel>
|
||||
<StackPanel>
|
||||
<TextBlock Foreground="Black" Margin="0,0,0,5">Stop Bits:</TextBlock>
|
||||
<ComboBox
|
||||
x:Name="stopBitsComboBox"
|
||||
|
||||
Margin="0"
|
||||
HorizontalAlignment="Center"
|
||||
Classes="noArrow"
|
||||
SelectedIndex="0"
|
||||
>
|
||||
<ComboBoxItem Tag="0" Content="0"/>
|
||||
<ComboBoxItem Tag="1" Content="1"/>
|
||||
<ComboBoxItem Tag="2" Content="2"/>
|
||||
<ComboBoxItem Tag="3" Content="1.5"/>
|
||||
</ComboBox>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
|
||||
<StackPanel>
|
||||
<TextBlock Foreground="Black" Margin="0,0,0,5">Parity:</TextBlock>
|
||||
<ComboBox
|
||||
x:Name="parityComboBox"
|
||||
|
||||
Margin="0"
|
||||
HorizontalAlignment="Center"
|
||||
Classes="noArrow"
|
||||
SelectedIndex="0"
|
||||
>
|
||||
<ComboBoxItem Tag="0" Content="NONE"/>
|
||||
<ComboBoxItem Tag="1" Content="ODD"/>
|
||||
<ComboBoxItem Tag="2" Content="EVEN"/>
|
||||
<ComboBoxItem Tag="4" Content="SPACE"/>
|
||||
<ComboBoxItem Tag="3" Content="MARK"/>
|
||||
</ComboBox>
|
||||
|
||||
</StackPanel>
|
||||
<StackPanel>
|
||||
<TextBlock Foreground="Black" Margin="0,0,0,5">Packets Sending Intervals :</TextBlock>
|
||||
<TextBox x:Name="sendingTimetxt"
|
||||
BorderBrush="#CCC"
|
||||
BorderThickness="1"
|
||||
GotFocus="ShowNumberKeyBoard"
|
||||
MaxLength="9"
|
||||
></TextBox>
|
||||
|
||||
|
||||
|
||||
</StackPanel>
|
||||
|
||||
|
||||
<!-- Button Panel -->
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Spacing="10">
|
||||
<!-- Save Button -->
|
||||
<Button x:Name="comSaveButton"
|
||||
Content="OK"
|
||||
FontSize="16"
|
||||
Padding="10,5"
|
||||
Click="comSaveClick"
|
||||
Foreground="White" >
|
||||
<Button.Background>
|
||||
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
|
||||
<GradientStop Color="#A4275D" Offset="0" />
|
||||
<GradientStop Color="#A4275D" Offset="1" />
|
||||
</LinearGradientBrush>
|
||||
</Button.Background>
|
||||
<Button.Effect>
|
||||
|
||||
</Button.Effect>
|
||||
</Button>
|
||||
<!-- Cancel Button -->
|
||||
<Button x:Name="CancelComButton"
|
||||
Content="Cancel"
|
||||
FontSize="16"
|
||||
Padding="10,5"
|
||||
Background="Gray"
|
||||
Foreground="White"
|
||||
Click="hideComPopUp"
|
||||
|
||||
>
|
||||
<Button.Effect>
|
||||
|
||||
</Button.Effect>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
<!-- Overlay Background for Com Settings Popup -->
|
||||
<Border x:Name="tempPopupOverlay" Background="#80000000" Grid.RowSpan="3" IsVisible="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" PointerPressed="hideTempPopUp">
|
||||
<!-- Popup User Control -->
|
||||
|
||||
<!-- Module for Name Entry -->
|
||||
<Grid PointerPressed="InnerPopupPointerPressed" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="20" IsVisible="True">
|
||||
<Border Background="White" CornerRadius="10" Padding="20" BorderThickness="1" ZIndex="101" BorderBrush="#CCC" >
|
||||
<StackPanel Spacing="15">
|
||||
<!-- Label for Text Input -->
|
||||
<!-- Label -->
|
||||
|
||||
<StackPanel Spacing="10">
|
||||
<TextBlock Foreground="Black" Margin="0,0,0,5">Warning Limit :</TextBlock>
|
||||
|
||||
<Border x:Name="warningBorder">
|
||||
<TextBox x:Name="warningLimit"
|
||||
BorderBrush="#CCC"
|
||||
BorderThickness="1"
|
||||
MaxLength="9"
|
||||
></TextBox>
|
||||
</Border>
|
||||
|
||||
|
||||
<TextBlock Foreground="Black" Margin="0,0,0,5">Error Limit :</TextBlock>
|
||||
|
||||
<Border x:Name="errorBorder">
|
||||
<TextBox x:Name="errorLimit"
|
||||
BorderBrush="#CCC"
|
||||
BorderThickness="1"
|
||||
MaxLength="9"
|
||||
></TextBox>
|
||||
</Border>
|
||||
|
||||
|
||||
|
||||
</StackPanel>
|
||||
|
||||
|
||||
<!-- Button Panel -->
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Spacing="10">
|
||||
<!-- Save Button -->
|
||||
<Button x:Name="tempSaveButton"
|
||||
Content="OK"
|
||||
FontSize="16"
|
||||
Padding="10,5"
|
||||
Click="tempSaveBtn"
|
||||
Foreground="White" >
|
||||
<Button.Background>
|
||||
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
|
||||
<GradientStop Color="#A4275D" Offset="0" />
|
||||
<GradientStop Color="#A4275D" Offset="1" />
|
||||
</LinearGradientBrush>
|
||||
</Button.Background>
|
||||
<Button.Effect>
|
||||
|
||||
</Button.Effect>
|
||||
</Button>
|
||||
<!-- Cancel Button -->
|
||||
<Button x:Name="CancelTempButton"
|
||||
Content="Cancel"
|
||||
FontSize="16"
|
||||
Padding="10,5"
|
||||
Background="Gray"
|
||||
Foreground="White"
|
||||
Click="hideTempPopUp"
|
||||
|
||||
>
|
||||
<Button.Effect>
|
||||
|
||||
</Button.Effect>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!--number keyBoard-->
|
||||
<Border x:Name="keyBoardPopup"
|
||||
Background="#80000000"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
IsVisible="False"
|
||||
ZIndex="50"
|
||||
PointerPressed="OnPopupOverlayPointerPressed">
|
||||
<Grid MaxWidth="500" MaxHeight="500" HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,150,0">
|
||||
<Border x:Name="PopupControl"
|
||||
BorderThickness="2"
|
||||
CornerRadius="10"
|
||||
Padding="10"
|
||||
PointerPressed="OnPopupOverlayPointerPressed">
|
||||
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Spacing="10">
|
||||
<!-- Popup Content (Keypad etc.) -->
|
||||
<Grid IsVisible="True">
|
||||
<Grid.Styles>
|
||||
<Style Selector="Button">
|
||||
<Setter Property="Background" Value="White"/>
|
||||
<Setter Property="CornerRadius" Value="20"/>
|
||||
<Setter Property="Width" Value="100"/>
|
||||
<Setter Property="Height" Value="100"/>
|
||||
<Setter Property="FontSize" Value="50"/>
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Center"/>
|
||||
</Style>
|
||||
<Style Selector="Button:pointerover /template/ContentPresenter">
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
<Setter Property="Background" Value="White"/>
|
||||
<Setter Property="CornerRadius" Value="20"/>
|
||||
<Setter Property="RenderTransform" Value="scale(1.11)"/>
|
||||
</Style>
|
||||
</Grid.Styles>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.Row="1" Margin="10">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="1*"/>
|
||||
<RowDefinition Height="1*"/>
|
||||
<RowDefinition Height="1*"/>
|
||||
<RowDefinition Height="1*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<!-- Keypad Buttons -->
|
||||
<Button Content="1" Grid.Row="0" Grid.Column="0" FontSize="24" Background="White" Margin="5" Click="OnKeyClick"/>
|
||||
<Button Content="2" Grid.Row="0" Grid.Column="1" FontSize="24" Background="White" Margin="5" Click="OnKeyClick"/>
|
||||
<Button Content="3" Grid.Row="0" Grid.Column="2" FontSize="24" Background="White" Margin="5" Click="OnKeyClick"/>
|
||||
<Button Content="4" Grid.Row="1" Grid.Column="0" FontSize="24" Background="White" Margin="5" Click="OnKeyClick"/>
|
||||
<Button Content="5" Grid.Row="1" Grid.Column="1" FontSize="24" Background="White" Margin="5" Click="OnKeyClick"/>
|
||||
<Button Content="6" Grid.Row="1" Grid.Column="2" FontSize="24" Background="White" Margin="5" Click="OnKeyClick"/>
|
||||
<Button Content="7" Grid.Row="2" Grid.Column="0" FontSize="24" Background="White" Margin="5" Click="OnKeyClick"/>
|
||||
<Button Content="8" Grid.Row="2" Grid.Column="1" FontSize="24" Background="White" Margin="5" Click="OnKeyClick"/>
|
||||
<Button Content="9" Grid.Row="2" Grid.Column="2" FontSize="24" Background="White" Margin="5" Click="OnKeyClick"/>
|
||||
<Button Content="BACK" Grid.Row="3" Grid.Column="0" FontSize="20" Background="#D3D3D3" Margin="5" Click="OnBackClick"/>
|
||||
<Button Content="0" Grid.Row="3" Grid.Column="1" FontSize="24" Background="White" Margin="5" Click="OnKeyClick"/>
|
||||
<Button Content="ENTER" Grid.Row="3" Grid.Column="2" FontSize="20" Background="#A4275D" Foreground="White" Margin="5" Click="EnterClick"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
698
DaireApplication/Views/UserController/Software.axaml.cs
Normal file
@@ -0,0 +1,698 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.LogicalTree;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Threading;
|
||||
using AvaloniaApplication1.DataBase;
|
||||
using DaireApplication.DataBase;
|
||||
using DaireApplication.ViewModels;
|
||||
using DaireApplication.Views;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Ports;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Reflection.Emit;
|
||||
using System.Reflection.PortableExecutable;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DaireApplication;
|
||||
|
||||
public partial class Software : UserControl
|
||||
{
|
||||
private MainWindow? _mainWindow;
|
||||
public UserTable _user = new();
|
||||
public ScreeenTable _screeen = new();
|
||||
private Process? _keyboardProcess;
|
||||
private bool _isWindowLoaded = false;
|
||||
TextBox targetText = new TextBox();
|
||||
int oldValue = 0;
|
||||
bool _isAdvSetting;
|
||||
bool _isFromManualControl;
|
||||
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
private void RaisePropertyChanged([CallerMemberName] string? name = null) =>
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
|
||||
|
||||
public ObservableCollection<string> SerialPorts { get; } = new() { "Choose COM" };
|
||||
|
||||
private string? _selectedPort;
|
||||
public string? SelectedPort
|
||||
{
|
||||
get => _selectedPort;
|
||||
set
|
||||
{
|
||||
if (_selectedPort != value)
|
||||
{
|
||||
_selectedPort = value;
|
||||
RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
public Software(MainWindow mainWindow,bool isAdvSetting=false, bool isFromManualControl=false)
|
||||
{
|
||||
_mainWindow = mainWindow;
|
||||
_isAdvSetting = isAdvSetting;
|
||||
_isFromManualControl = isFromManualControl;
|
||||
foreach (var port in SerialPort.GetPortNames())
|
||||
{
|
||||
SerialPorts.Add(port);
|
||||
}
|
||||
var screen = _screeen.ReadScreens()[0];
|
||||
|
||||
InitializeComponent();
|
||||
this.Loaded += OnWindowLoaded;
|
||||
if (SerialPorts.Count - 1 > 0)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(screen.port))
|
||||
{
|
||||
SerialPorts[0] = "Close Comunication";
|
||||
SelectedPort = screen.port;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
SerialPorts[0] = "Choose COM";
|
||||
|
||||
SelectedPort = SerialPorts[0];
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
SelectedPort = SerialPorts[0];
|
||||
DataContext = this;
|
||||
|
||||
setDefaultSettings();
|
||||
showDefaultValues();
|
||||
sendingTimetxt.AddHandler(TextInputEvent, OnTextInput, RoutingStrategies.Tunnel);
|
||||
warningLimit.AddHandler(TextInputEvent, OnTextInput, RoutingStrategies.Tunnel);
|
||||
errorLimit.AddHandler(TextInputEvent, OnTextInput, RoutingStrategies.Tunnel);
|
||||
passwordBorder.AddHandler(InputElement.PointerPressedEvent, OnTextBoxFocused, RoutingStrategies.Tunnel, handledEventsToo: true);
|
||||
warningBorder.AddHandler(InputElement.PointerPressedEvent, OnTextBoxFocused, RoutingStrategies.Tunnel, handledEventsToo: true);
|
||||
errorBorder.AddHandler(InputElement.PointerPressedEvent, OnTextBoxFocused, RoutingStrategies.Tunnel, handledEventsToo: true);
|
||||
AttachHandlers(_mainWindow.logoBtn, AdvanceSettingsView);
|
||||
AttachHandlers(_mainWindow.UserName, CloseApplication);
|
||||
|
||||
}
|
||||
public void AttachHandlers(Button button, System.EventHandler<Avalonia.Input.HoldingRoutedEventArgs> func)
|
||||
{
|
||||
if (button != null)
|
||||
{
|
||||
button.Holding += func;
|
||||
|
||||
button.PointerPressed += (sender, e) =>
|
||||
{
|
||||
// Simulate a long press on any pointer (mouse or touch)
|
||||
var point = e.GetPosition(button);
|
||||
func(sender, new HoldingRoutedEventArgs(HoldingState.Started, point, e.Pointer.Type));
|
||||
};
|
||||
|
||||
button.PointerReleased += (sender, e) =>
|
||||
{
|
||||
// End simulated long press
|
||||
var point = e.GetPosition(button);
|
||||
func(sender, new HoldingRoutedEventArgs(HoldingState.Completed, point, e.Pointer.Type));
|
||||
};
|
||||
}
|
||||
}
|
||||
public Software()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
}
|
||||
public void AdvanceSettingsView(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_mainWindow.ContentArea.Content == this)
|
||||
{
|
||||
_mainWindow.ContentArea.Content = new AdvanceSettings(_mainWindow,false,true);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
public static void CloseApplication(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var lifetime = Application.Current?.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime;
|
||||
lifetime?.Shutdown(); // This should correctly shut down the application
|
||||
}
|
||||
private void OnWindowLoaded(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
_isWindowLoaded = true;
|
||||
}
|
||||
private void OnTextInput(object? sender, TextInputEventArgs e)
|
||||
{
|
||||
if (sender is TextBox textBox)
|
||||
{
|
||||
string newText = textBox.Text + e.Text;
|
||||
if (!Regex.IsMatch(newText, @"^\d*\.?\d*$"))
|
||||
{
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void hidePasswordPopUp(object sender, RoutedEventArgs e)
|
||||
{
|
||||
|
||||
passwordInput.Text = "";
|
||||
CloseKeyboard();
|
||||
passwordPopupOverlay.IsVisible = false;
|
||||
}
|
||||
private async void passwordSaveClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var user = _user.ReadUsers().FirstOrDefault(x=>x.UserName.ToLower()==titelMsg.Tag.ToString().ToLower());
|
||||
user.Password = passwordInput.Text;
|
||||
user.IsActive = isActivePass.IsChecked.Value;
|
||||
if (_user.UpdateUser(user))
|
||||
{
|
||||
//await MainWindow.MessageBox.Show(_mainWindow, "Password Changed Sucseccfully", "Sucsecc");
|
||||
passwordInput.Text = "";
|
||||
CloseKeyboard();
|
||||
|
||||
passwordPopupOverlay.IsVisible = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_keyboardProcess != null)
|
||||
{
|
||||
_keyboardProcess.Kill();
|
||||
}
|
||||
await MainWindow.MessageBox.Show(_mainWindow, "Password Does Not Changed Try Again", "Error");
|
||||
_mainWindow.Topmost = false;
|
||||
}
|
||||
|
||||
}
|
||||
private void showChangePasswordPopUp(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Button button)
|
||||
{
|
||||
var text = button.Content as TextBlock;
|
||||
titelMsg.Text = $"New {text.Text} Password:";
|
||||
titelMsg.Tag = text.Text;
|
||||
var user = _user.ReadUsers().FirstOrDefault(x => x.UserName.ToLower() == titelMsg.Tag.ToString().ToLower());
|
||||
isActivePass.IsVisible = true;
|
||||
isActivePass.IsChecked = user.IsActive;
|
||||
passwordPopupOverlay.IsVisible = true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void hideScreenPopUp(object sender, RoutedEventArgs e)
|
||||
{
|
||||
slider.Value = 0;
|
||||
secreenPopupOverlay.IsVisible = false;
|
||||
}
|
||||
private async void screenSaveClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var screenData = _screeen.ReadScreens()?[0];
|
||||
string brightnessPath = "/sys/class/backlight/backlight/brightness"; // Try backlight1 if this fails
|
||||
|
||||
if (titelSecreenMsg.Tag.ToString()== "BRIGHTNESS")
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!string.IsNullOrEmpty(sliderValue.Text))
|
||||
{
|
||||
int brightnessValue = (int)(Int32.Parse(sliderValue.Text) / 100.0 * 255);
|
||||
screenData.brightness = Int32.Parse(sliderValue.Text);
|
||||
_screeen.UpdateScreen(screenData);
|
||||
File.WriteAllText(brightnessPath, brightnessValue.ToString());
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Error: " + ex.Message);
|
||||
}
|
||||
}
|
||||
else if (titelSecreenMsg.Tag.ToString() == "AUTO DIM")
|
||||
{
|
||||
if (!string.IsNullOrEmpty(sliderValue.Text))
|
||||
{
|
||||
if ((screenData?.offSec / 60.0) < float.Parse(sliderValue.Text))
|
||||
{
|
||||
if (_keyboardProcess != null)
|
||||
{
|
||||
_keyboardProcess.Kill();
|
||||
}
|
||||
await MainWindow.MessageBox.Show(_mainWindow, "AutoOff Value must be greater than AutoDim Value", "Error");
|
||||
_mainWindow.Topmost = false;
|
||||
return;
|
||||
}
|
||||
screenData.dimSec = float.Parse(sliderValue.Text) * 60;
|
||||
|
||||
_screeen.UpdateScreen(screenData);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else if (titelSecreenMsg.Tag.ToString() == "AUTO OFF")
|
||||
{
|
||||
if (!string.IsNullOrEmpty(sliderValue.Text))
|
||||
{
|
||||
if ((screenData?.dimSec / 60.0)> float.Parse(sliderValue.Text))
|
||||
{
|
||||
if (_keyboardProcess != null)
|
||||
{
|
||||
_keyboardProcess.Kill();
|
||||
}
|
||||
await MainWindow.MessageBox.Show(_mainWindow, "AutoOff Value must be greater than AutoDim Value", "Error");
|
||||
_mainWindow.Topmost = false;
|
||||
|
||||
return;
|
||||
}
|
||||
screenData.offSec = float.Parse(sliderValue.Text) * 60;
|
||||
|
||||
_screeen.UpdateScreen(screenData);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
showDefaultValues();
|
||||
secreenPopupOverlay.IsVisible = false;
|
||||
|
||||
|
||||
}
|
||||
private void InnerPopupPointerPressed(object? sender, PointerPressedEventArgs e)
|
||||
{
|
||||
e.Handled = true;
|
||||
}
|
||||
private void showScreenPopUp(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Button button)
|
||||
{
|
||||
var screenData = _screeen.ReadScreens()?[0];
|
||||
|
||||
if (button.Tag.ToString() == "BRIGHTNESS")
|
||||
{
|
||||
slider.Maximum = 100;
|
||||
titelSecreenMsg.Text = $"Enter {button.Tag} percentage:";
|
||||
titelSecreenMsg.Tag = button.Tag;
|
||||
slider.Value = screenData.brightness;
|
||||
secreenPopupOverlay.IsVisible = true;
|
||||
}
|
||||
if (button.Tag.ToString() == "AUTO DIM")
|
||||
{
|
||||
slider.Maximum = 120;
|
||||
|
||||
titelSecreenMsg.Text = $"Enter {button.Tag} value in min:";
|
||||
titelSecreenMsg.Tag = button.Tag;
|
||||
slider.Value = screenData.dimSec / 60;
|
||||
|
||||
secreenPopupOverlay.IsVisible = true;
|
||||
}
|
||||
if (button.Tag.ToString() == "AUTO OFF")
|
||||
{
|
||||
slider.Maximum = 120;
|
||||
|
||||
titelSecreenMsg.Text = $"Enter {button.Tag} value in min:";
|
||||
titelSecreenMsg.Tag = button.Tag;
|
||||
slider.Value = screenData.offSec / 60;
|
||||
|
||||
secreenPopupOverlay.IsVisible = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
private void OnSliderValueChanged(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Slider slider)
|
||||
{
|
||||
var parent = slider.Parent as StackPanel;
|
||||
var targetText = parent.Children[1] as TextBlock;
|
||||
|
||||
targetText.Text= slider.Value.ToString();
|
||||
//sliderValue.Text= slider.Value.ToString();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
private void changeValueClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Button button)
|
||||
{
|
||||
var parent = button.Parent as StackPanel;
|
||||
var slider = parent.Children[1] as Slider;
|
||||
var grandParent = parent.Parent as StackPanel;
|
||||
var stack = grandParent.Children[0] as StackPanel;
|
||||
var targetText = stack.Children[1] as TextBlock;
|
||||
targetText.Text = slider.Value.ToString();
|
||||
if (button.Content=="+") // +
|
||||
{
|
||||
slider.Value = Int32.Parse(targetText.Text) + 1;
|
||||
|
||||
}
|
||||
else // -
|
||||
{
|
||||
if (Int32.Parse(targetText.Text)>0)
|
||||
{
|
||||
slider.Value = Int32.Parse(targetText.Text) - 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
private void OnComSliderValueChanged(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Slider slider)
|
||||
{
|
||||
var parent = slider.Parent.Parent as StackPanel;
|
||||
var stack = parent.Children[0] as StackPanel;
|
||||
var targetText = stack.Children[1] as TextBlock;
|
||||
targetText.Text= slider.Value.ToString();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
private void hideComPopUp(object sender, RoutedEventArgs e)
|
||||
{
|
||||
//comSlider.Value = 0;
|
||||
comPopupOverlay.IsVisible = false;
|
||||
}
|
||||
private void hideTempPopUp(object sender, RoutedEventArgs e)
|
||||
{
|
||||
tempPopupOverlay.IsVisible = false;
|
||||
}
|
||||
private async void comSaveClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var screen = _screeen.ReadScreens()[0];
|
||||
var boundRateItem = boundRateComboBox.SelectedItem as ComboBoxItem;
|
||||
screen.boundRate = Int32.Parse(boundRateItem.Content.ToString());
|
||||
var stopbitsItem = stopBitsComboBox.SelectedItem as ComboBoxItem;
|
||||
screen.stopBits = Int32.Parse(stopbitsItem.Tag.ToString());
|
||||
var parityItem = parityComboBox.SelectedItem as ComboBoxItem;
|
||||
screen.parity = Int32.Parse(parityItem.Tag.ToString());
|
||||
screen.sendingTime = Int32.Parse(sendingTimetxt.Text);
|
||||
|
||||
if (_screeen.UpdateScreen(screen))
|
||||
{
|
||||
_mainWindow.resetPort = true;
|
||||
_mainWindow.footerMsg.Text = "Connecting.....";
|
||||
_mainWindow.footerMsg.IsVisible = true;
|
||||
comPopupOverlay.IsVisible = false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
private void showComPopUp(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var screen = _screeen.ReadScreens()[0];
|
||||
|
||||
boundRateComboBox.SelectedIndex=int.Parse(boundRateComboBox.Items.OfType<ComboBoxItem>().FirstOrDefault(item => item.Content?.ToString() == screen.boundRate.ToString()).Tag.ToString());
|
||||
stopBitsComboBox.SelectedIndex = screen.stopBits;
|
||||
parityComboBox.SelectedIndex = screen.parity;
|
||||
sendingTimetxt.Text=screen.sendingTime.ToString();
|
||||
comPopupOverlay.IsVisible = true;
|
||||
}
|
||||
private void ShowTempPopUp(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var screen = _screeen.ReadScreens()[0];
|
||||
warningLimit.Text=screen.warningLimit.ToString();
|
||||
errorLimit.Text=screen.errorLimit.ToString();
|
||||
tempPopupOverlay.IsVisible = true;
|
||||
}
|
||||
private void tempSaveBtn(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var screen = _screeen.ReadScreens()[0];
|
||||
screen.warningLimit = double.Parse(warningLimit.Text);
|
||||
screen.errorLimit = double.Parse(errorLimit.Text);
|
||||
_screeen.UpdateScreen(screen);
|
||||
CloseKeyboard();
|
||||
//if (_keyboardProcess != null)
|
||||
//{
|
||||
// _keyboardProcess.Kill();
|
||||
|
||||
//}
|
||||
|
||||
tempPopupOverlay.IsVisible=false;
|
||||
}
|
||||
private void portChanged(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!_isWindowLoaded)
|
||||
return;
|
||||
if (sender is ComboBox comboBox)
|
||||
{
|
||||
if (comboBox.SelectedItem is string selectedItem)
|
||||
{
|
||||
var screen = _screeen.ReadScreens()[0];
|
||||
if (selectedItem.ToString()!= "Choose COM" && selectedItem.ToString()!= "Close Comunication")
|
||||
{
|
||||
screen.port = selectedItem.ToString();
|
||||
_screeen.UpdateScreen(screen);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
screen.port = "";
|
||||
_screeen.UpdateScreen(screen);
|
||||
}
|
||||
boundRateComboBox.SelectedIndex = int.Parse(boundRateComboBox.Items.OfType<ComboBoxItem>().FirstOrDefault(item => item.Content?.ToString() == screen.boundRate.ToString()).Tag.ToString());
|
||||
stopBitsComboBox.SelectedIndex = screen.stopBits;
|
||||
parityComboBox.SelectedIndex = screen.parity;
|
||||
sendingTimetxt.Text = screen.sendingTime.ToString();
|
||||
this.comSaveButton.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private (string? fileName, string args) GetKeyboardCommand()
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
return ("osk.exe", "");
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
return ("onboard", ""); // or "florence", "matchbox-keyboard"
|
||||
return (null, "");
|
||||
}
|
||||
|
||||
private async void OnTextBoxFocused(object? sender, PointerPressedEventArgs e)
|
||||
{
|
||||
if (_keyboardProcess is { HasExited: false })
|
||||
return;
|
||||
|
||||
var (fileName, args) = GetKeyboardCommand();
|
||||
if (fileName is null)
|
||||
return;
|
||||
|
||||
_keyboardProcess = new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = fileName,
|
||||
Arguments = args,
|
||||
UseShellExecute = true,
|
||||
WorkingDirectory = "/usr/bin"
|
||||
},
|
||||
EnableRaisingEvents = true
|
||||
};
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
_keyboardProcess.Start();
|
||||
|
||||
|
||||
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
if (sender is Border border)
|
||||
{
|
||||
var textbox = border.Child as TextBox;
|
||||
textbox.SelectionStart = 0;
|
||||
textbox.SelectionEnd = textbox.Text?.Length ?? 0;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
catch
|
||||
{
|
||||
// fail silently if keyboard not found
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void OnPopupOverlayPointerPressed(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
targetText.Text = oldValue.ToString();
|
||||
CancelComButton.Focus();
|
||||
|
||||
keyBoardPopup.IsVisible = false;
|
||||
}
|
||||
private void OnKeyClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Button button)
|
||||
{
|
||||
targetText.Text += button.Content;
|
||||
}
|
||||
}
|
||||
private void ShowNumberKeyBoard(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
targetText = sendingTimetxt;
|
||||
oldValue = Int32.Parse(targetText.Text);
|
||||
targetText.Text = "";
|
||||
keyBoardPopup.IsVisible = true;
|
||||
}
|
||||
private void OnBackClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(targetText.Text))
|
||||
{
|
||||
// Remove the last character from the text box
|
||||
targetText.Text = targetText.Text.Remove(targetText.Text.Length - 1, 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void EnterClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
|
||||
CancelComButton.Focus();
|
||||
keyBoardPopup.IsVisible = false;
|
||||
}
|
||||
|
||||
private void CloseKeyboard()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_keyboardProcess != null)
|
||||
{
|
||||
// Kill the keyboard process
|
||||
_keyboardProcess.Kill();
|
||||
_keyboardProcess.Dispose();
|
||||
_keyboardProcess = null;
|
||||
|
||||
// Force kill any remaining keyboard processes
|
||||
var processKill = new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = "killall",
|
||||
Arguments = "-9 onboard matchbox-keyboard florence", // Common Linux on-screen keyboards
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true
|
||||
}
|
||||
};
|
||||
processKill.Start();
|
||||
processKill.WaitForExit(1000);
|
||||
processKill.Dispose();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error closing keyboard: {ex.Message}");
|
||||
}
|
||||
}
|
||||
private void setDefaultSettings()
|
||||
{
|
||||
_mainWindow.minimizeBtn.IsVisible = false;
|
||||
|
||||
var stackPanel = _mainWindow.HomeTrack.Parent as StackPanel;
|
||||
|
||||
if (_isFromManualControl)
|
||||
{
|
||||
// Special UI setup when called from ManualControl
|
||||
_mainWindow.HomeTrack.IsVisible = true;
|
||||
_mainWindow.HomePolygon.Stroke = Avalonia.Media.Brushes.Black;
|
||||
_mainWindow.RecipeSelTrack.IsVisible = false;
|
||||
_mainWindow.RunInterfaceTrack.IsVisible = false;
|
||||
_mainWindow.RecipePanelTrack.IsVisible = true;
|
||||
_mainWindow.RecipePanelPolygon.Stroke = Avalonia.Media.Brushes.Black;
|
||||
_mainWindow.RecipeEditTrack.IsVisible = false;
|
||||
_mainWindow.SettingTrack.IsVisible = false;
|
||||
_mainWindow.AdvanceSettingsTrack.IsVisible = false;
|
||||
_mainWindow.ManualControlTrack.IsVisible = true;
|
||||
_mainWindow.ManualControlPolygon.Stroke = Avalonia.Media.Brushes.Black;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Original logic for other callers
|
||||
//Set Track Up
|
||||
_mainWindow.HomeTrack.IsVisible = true;
|
||||
_mainWindow.HomePolygon.Stroke = Avalonia.Media.Brushes.Black;
|
||||
_mainWindow.RecipeSelTrack.IsVisible = false;
|
||||
_mainWindow.RunInterfaceTrack.IsVisible = false;
|
||||
_mainWindow.RecipePanelTrack.IsVisible = false;
|
||||
_mainWindow.RecipeEditTrack.IsVisible = false;
|
||||
if (_isAdvSetting)
|
||||
{
|
||||
_mainWindow.SettingTrack.IsVisible = false;
|
||||
_mainWindow.AdvanceSettingsTrack.IsVisible = true;
|
||||
_mainWindow.AdvanceSettingsPolygon.Stroke = Avalonia.Media.Brushes.Black;
|
||||
}
|
||||
else
|
||||
{
|
||||
_mainWindow.SettingTrack.IsVisible = true;
|
||||
_mainWindow.SettingPolygon.Stroke = Avalonia.Media.Brushes.Black;
|
||||
_mainWindow.AdvanceSettingsTrack.IsVisible = false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
_mainWindow.DiagnosticsTrack.IsVisible = false;
|
||||
// Remove the button from its current position
|
||||
stackPanel.Children.Remove(_mainWindow.SoftwareTrack);
|
||||
|
||||
// Add it back at the end of the StackPanel
|
||||
stackPanel.Children.Add(_mainWindow.SoftwareTrack);
|
||||
_mainWindow.SoftwareTrack.IsVisible = true;
|
||||
_mainWindow.SoftwarePolygon.Stroke = Brush.Parse("#A4275D");
|
||||
|
||||
|
||||
_mainWindow.TitleBtn.IsVisible = false;
|
||||
//Set Footer
|
||||
_mainWindow.footerMsg.IsVisible = false;
|
||||
_mainWindow.footer.Background = Brush.Parse("#f2f2f2");
|
||||
_mainWindow.footerDate.Text = DateTime.Now.ToString("dd/MM/yyyy");
|
||||
_mainWindow.footerTime.Text = DateTime.Now.ToString("hh:mm tt");
|
||||
_mainWindow.footerDateContainer.IsVisible = true;
|
||||
_mainWindow.footerStartBtn.IsVisible = false;
|
||||
_mainWindow.adminBtns.IsVisible = false;
|
||||
}
|
||||
|
||||
private void showDefaultValues()
|
||||
{
|
||||
var users = _user.ReadUsers();
|
||||
var allUIUsers = this.GetLogicalDescendants()
|
||||
.OfType<TextBlock>()
|
||||
.Where(cb => cb.Classes.Contains("user"))
|
||||
.ToList();
|
||||
for (int i = 0; i < allUIUsers.Count; i++)
|
||||
{
|
||||
allUIUsers[i].Text = users[i].UserName;
|
||||
}
|
||||
var screenData = _screeen.ReadScreens()?[0];
|
||||
|
||||
brightnessValue.Text = screenData?.brightness.ToString();
|
||||
dimValue.Text = (screenData?.dimSec/60.0).ToString();
|
||||
offValue.Text = (screenData?.offSec/60.0).ToString();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
18
DaireApplication/app.manifest
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<!-- This manifest is used on Windows only.
|
||||
Don't remove it as it might cause problems with window transparency and embedded controls.
|
||||
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
|
||||
<assemblyIdentity version="1.0.0.0" name="DaireApplication.Desktop"/>
|
||||
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- A list of the Windows versions that this application has been tested on
|
||||
and is designed to work with. Uncomment the appropriate elements
|
||||
and Windows will automatically select the most compatible environment. -->
|
||||
|
||||
<!-- Windows 10 -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||
</application>
|
||||
</compatibility>
|
||||
</assembly>
|
||||