Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a0b3adc288 | |||
| 44ac517223 | |||
| c609e0e90e |
@@ -49,3 +49,7 @@ android/key.properties
|
|||||||
windows/installer/*
|
windows/installer/*
|
||||||
bugreport*
|
bugreport*
|
||||||
!downloads/*
|
!downloads/*
|
||||||
|
android/builds.json
|
||||||
|
macos/builds.json
|
||||||
|
ios/builds.json
|
||||||
|
windows/busylight-buddy-windows-installer-builder.iss
|
||||||
@@ -1,23 +1,93 @@
|
|||||||
$buildType = if ($args[0]) { $args[0] } else { "debug" }
|
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Builds a Flutter APK with versioning support.
|
||||||
|
|
||||||
|
.DESCRIPTION
|
||||||
|
This script builds a Flutter APK, manages build numbers, and renames output files.
|
||||||
|
|
||||||
|
.PARAMETER buildType
|
||||||
|
The build type (release or debug). Default is "release".
|
||||||
|
|
||||||
|
.PARAMETER buildName
|
||||||
|
The build name (version). Default is "0.0.0".
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
.\flutter-build-apk.ps1 -buildType debug -buildName 1.0.0
|
||||||
|
Builds a debug APK with version 1.0.0.
|
||||||
|
#>
|
||||||
|
|
||||||
|
[CmdletBinding()]
|
||||||
|
param (
|
||||||
|
[string]$buildType = "release", # Default value is "release"
|
||||||
|
[string]$buildName = "0.0.0" # Default value is "0.0.0"
|
||||||
|
)
|
||||||
|
|
||||||
|
$buildsRef = "builds.json"
|
||||||
|
|
||||||
|
# Check if the file exists
|
||||||
|
if (-not (Test-Path -Path $buildsRef)) {
|
||||||
|
# Create the file if it doesn't exist
|
||||||
|
New-Item -Path $buildsRef -ItemType File
|
||||||
|
$buildsMap = @{
|
||||||
|
$buildName = 0
|
||||||
|
}
|
||||||
|
$buildsMap | ConvertTo-Json | Out-File $buildsRef
|
||||||
|
Write-Output "File created: $buildsRef"
|
||||||
|
} else {
|
||||||
|
Write-Output "File already exists: $buildsRef"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Read the JSON file and convert it to a hashtable
|
||||||
|
$jsonContent = Get-Content $buildsRef -Raw | ConvertFrom-Json
|
||||||
|
$buildsMap = @{}
|
||||||
|
$jsonContent.PSObject.Properties | ForEach-Object {
|
||||||
|
$buildsMap[$_.Name] = $_.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($buildsMap.ContainsKey($buildName)) {
|
||||||
|
Write-Output "Build exists: $buildName"
|
||||||
|
$buildNumber = $buildsMap[$buildName]
|
||||||
|
$buildNumber++
|
||||||
|
Write-Output "Next build number for ${buildName}: $buildNumber"
|
||||||
|
$buildsMap[$buildName] = $buildNumber
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$buildsMap[$buildName] = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
$buildsMap | ConvertTo-Json | Out-File $buildsRef
|
||||||
|
|
||||||
|
|
||||||
$apkDir = "..\build\app\outputs\flutter-apk"
|
$apkDir = "..\build\app\outputs\flutter-apk"
|
||||||
$baseName = "org.igox.apps.android.busylight-buddy"
|
$baseName = "org.igox.apps.android.busylight-buddy"
|
||||||
|
|
||||||
flutter build apk --$buildType
|
# Build an array for arguments
|
||||||
|
$flutterArgs = @(
|
||||||
|
"--$buildType",
|
||||||
|
"--build-name=$buildName",
|
||||||
|
"--build-number=$buildNumber",
|
||||||
|
"--target-platform=android-arm,android-arm64,android-x64"
|
||||||
|
)
|
||||||
|
|
||||||
|
Write-Output "Building APK with arguments: $($flutterArgs -join ' ')"
|
||||||
|
|
||||||
|
& flutter build apk @flutterArgs
|
||||||
|
|
||||||
# Rename APK
|
# Rename APK
|
||||||
$oldApk = "$apkDir\app-$buildType.apk"
|
$oldApk = "$apkDir\app-${buildType}.apk"
|
||||||
$newApk = "$apkDir\$baseName-$buildType.apk"
|
$newApk = "$apkDir\$baseName-${buildType}.apk"
|
||||||
if (Test-Path $oldApk) {
|
if (Test-Path $oldApk) {
|
||||||
if (Test-Path $newApk) { Remove-Item $newApk -Force }
|
if (Test-Path $newApk) { Remove-Item $newApk -Force }
|
||||||
Rename-Item -Path $oldApk -NewName "$baseName-$buildType.apk"
|
Rename-Item -Path $oldApk -NewName "$baseName-${buildType}.apk"
|
||||||
Write-Host "APK renamed to: $baseName-$buildType.apk"
|
Write-Host "APK renamed to: $baseName-${buildType}.apk"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Rename SHA1 (if exists)
|
# Rename SHA1 (if exists)
|
||||||
$oldSha1 = "$apkDir\app-$buildType.apk.sha1"
|
$oldSha1 = "$apkDir\app-${buildType}.apk.sha1"
|
||||||
$newSha1 = "$apkDir\$baseName-$buildType.apk.sha1"
|
$newSha1 = "$apkDir\$baseName-${buildType}.apk.sha1"
|
||||||
if (Test-Path $oldSha1) {
|
if (Test-Path $oldSha1) {
|
||||||
if (Test-Path $newSha1) { Remove-Item $newSha1 -Force }
|
if (Test-Path $newSha1) { Remove-Item $newSha1 -Force }
|
||||||
Rename-Item -Path $oldSha1 -NewName "$baseName-$buildType.apk.sha1"
|
Rename-Item -Path $oldSha1 -NewName "$baseName-${buildType}.apk.sha1"
|
||||||
Write-Host "SHA1 renamed to: $baseName-$buildType.apk.sha1"
|
Write-Host "SHA1 renamed to: $baseName-${buildType}.apk.sha1"
|
||||||
}
|
}
|
||||||
@@ -1,24 +1,90 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
BUILD_TYPE=${1:-debug}
|
|
||||||
APK_DIR="../build/app/outputs/flutter-apk"
|
|
||||||
BASE_NAME="org.igox.apps.android.busylight-buddy"
|
|
||||||
|
|
||||||
flutter build apk --$BUILD_TYPE
|
# Default values
|
||||||
|
buildType="release"
|
||||||
|
buildName="0.0.0"
|
||||||
|
buildsRef="builds.json"
|
||||||
|
|
||||||
|
# Help message
|
||||||
|
show_help() {
|
||||||
|
echo "Usage: $0 [-t buildType] [-n buildName]"
|
||||||
|
echo "Builds a Flutter APK with versioning support."
|
||||||
|
echo ""
|
||||||
|
echo "Options:"
|
||||||
|
echo " -t, --buildType Build type (release or debug). Default: release"
|
||||||
|
echo " -n, --buildName Build name (version). Default: 0.0.0"
|
||||||
|
echo " -h, --help Show this help message"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Parse command-line arguments
|
||||||
|
while [[ "$#" -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
-t|--buildType) buildType="$2"; shift ;;
|
||||||
|
-n|--buildName) buildName="$2"; shift ;;
|
||||||
|
-h|--help) show_help ;;
|
||||||
|
*) echo "Unknown parameter: $1"; show_help; exit 1 ;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
# Check if builds.json exists
|
||||||
|
if [ ! -f "$buildsRef" ]; then
|
||||||
|
echo "File created: $buildsRef"
|
||||||
|
echo "{\"$buildName\": 0}" > "$buildsRef"
|
||||||
|
else
|
||||||
|
echo "File already exists: $buildsRef"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Read the JSON file
|
||||||
|
buildsMap=$(cat "$buildsRef")
|
||||||
|
|
||||||
|
# Check if buildName exists in the JSON
|
||||||
|
if jq -e --arg key "$buildName" 'has($key)' <<< "$buildsMap" > /dev/null; then
|
||||||
|
echo "Build exists: $buildName"
|
||||||
|
buildNumber=$(jq --arg key "$buildName" '.[$key]' <<< "$buildsMap")
|
||||||
|
buildNumber=$((buildNumber + 1))
|
||||||
|
echo "Next build number for $buildName: $buildNumber"
|
||||||
|
buildsMap=$(jq --arg key "$buildName" --argjson value "$buildNumber" '.[$key] = $value' <<< "$buildsMap")
|
||||||
|
else
|
||||||
|
echo "New build: $buildName, starting at build number: 1"
|
||||||
|
buildNumber=1
|
||||||
|
buildsMap=$(jq --arg key "$buildName" --argjson value "$buildNumber" '.[$key] = $value' <<< "$buildsMap")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Save the updated JSON back to the file
|
||||||
|
echo "$buildsMap" > "$buildsRef"
|
||||||
|
|
||||||
|
# Define paths
|
||||||
|
apkDir="../build/app/outputs/flutter-apk"
|
||||||
|
baseName="org.igox.apps.android.busylight-buddy"
|
||||||
|
|
||||||
|
# Build APK
|
||||||
|
echo "Building APK with arguments: --$buildType --build-name=$buildName --build-number=$buildNumber --target-platform=android-arm,android-arm64,android-x64"
|
||||||
|
flutter build apk --"$buildType" --build-name="$buildName" --build-number="$buildNumber" --target-platform=android-arm,android-arm64,android-x64
|
||||||
|
|
||||||
# Rename APK
|
# Rename APK
|
||||||
OLD_APK="$APK_DIR/app-$BUILD_TYPE.apk"
|
oldApk="$apkDir/app-$buildType.apk"
|
||||||
NEW_APK="$APK_DIR/$BASE_NAME-$BUILD_TYPE.apk"
|
newApk="$apkDir/$baseName-$buildType.apk"
|
||||||
if [ -f "$OLD_APK" ]; then
|
if [ -f "$oldApk" ]; then
|
||||||
[ -f "$NEW_APK" ] && rm -f "$NEW_APK"
|
if [ -f "$newApk" ]; then
|
||||||
mv "$OLD_APK" "$NEW_APK"
|
rm -f "$newApk"
|
||||||
echo "APK renamed to: $BASE_NAME-$BUILD_TYPE.apk"
|
fi
|
||||||
|
mv "$oldApk" "$newApk"
|
||||||
|
echo "APK renamed to: $baseName-$buildType.apk"
|
||||||
|
else
|
||||||
|
echo "Warning: APK not found at $oldApk"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Rename SHA1 (if exists)
|
# Rename SHA1 (if exists)
|
||||||
OLD_SHA1="$APK_DIR/app-$BUILD_TYPE.apk.sha1"
|
oldSha1="$apkDir/app-$buildType.apk.sha1"
|
||||||
NEW_SHA1="$APK_DIR/$BASE_NAME-$BUILD_TYPE.apk.sha1"
|
newSha1="$apkDir/$baseName-$buildType.apk.sha1"
|
||||||
if [ -f "$OLD_SHA1" ]; then
|
if [ -f "$oldSha1" ]; then
|
||||||
[ -f "$NEW_SHA1" ] && rm -f "$NEW_SHA1"
|
if [ -f "$newSha1" ]; then
|
||||||
mv "$OLD_SHA1" "$NEW_SHA1"
|
rm -f "$newSha1"
|
||||||
echo "SHA1 renamed to: $BASE_NAME-$BUILD_TYPE.apk.sha1"
|
fi
|
||||||
|
mv "$oldSha1" "$newSha1"
|
||||||
|
echo "SHA1 renamed to: $baseName-$buildType.apk.sha1"
|
||||||
|
else
|
||||||
|
echo "Warning: SHA1 not found at $oldSha1"
|
||||||
fi
|
fi
|
||||||
Executable
+60
@@ -0,0 +1,60 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Default values
|
||||||
|
buildType="release"
|
||||||
|
buildName="0.0.0"
|
||||||
|
buildsRef="builds.json"
|
||||||
|
|
||||||
|
# Help message
|
||||||
|
show_help() {
|
||||||
|
echo "Usage: $0 [-t buildType] [-n buildName]"
|
||||||
|
echo "Builds a Flutter iOS application with versioning support."
|
||||||
|
echo ""
|
||||||
|
echo "Options:"
|
||||||
|
echo " -t, --buildType Build type (release or debug). Default: release"
|
||||||
|
echo " -n, --buildName Build name (version). Default: 0.0.0"
|
||||||
|
echo " -h, --help Show this help message"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Parse command-line arguments
|
||||||
|
while [[ "$#" -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
-t|--buildType) buildType="$2"; shift ;;
|
||||||
|
-n|--buildName) buildName="$2"; shift ;;
|
||||||
|
-h|--help) show_help ;;
|
||||||
|
*) echo "Unknown parameter: $1"; show_help; exit 1 ;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
# Check if builds.json exists
|
||||||
|
if [ ! -f "$buildsRef" ]; then
|
||||||
|
echo "File created: $buildsRef"
|
||||||
|
echo "{\"$buildName\": 0}" > "$buildsRef"
|
||||||
|
else
|
||||||
|
echo "File already exists: $buildsRef"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Read the JSON file
|
||||||
|
buildsMap=$(cat "$buildsRef")
|
||||||
|
|
||||||
|
# Check if buildName exists in the JSON
|
||||||
|
if jq -e --arg key "$buildName" 'has($key)' <<< "$buildsMap" > /dev/null; then
|
||||||
|
echo "Build exists: $buildName"
|
||||||
|
buildNumber=$(jq --arg key "$buildName" '.[$key]' <<< "$buildsMap")
|
||||||
|
buildNumber=$((buildNumber + 1))
|
||||||
|
echo "Next build number for $buildName: $buildNumber"
|
||||||
|
buildsMap=$(jq --arg key "$buildName" --argjson value "$buildNumber" '.[$key] = $value' <<< "$buildsMap")
|
||||||
|
else
|
||||||
|
echo "New build: $buildName, starting at build number: 1"
|
||||||
|
buildNumber=1
|
||||||
|
buildsMap=$(jq --arg key "$buildName" --argjson value "$buildNumber" '.[$key] = $value' <<< "$buildsMap")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Save the updated JSON back to the file
|
||||||
|
echo "$buildsMap" > "$buildsRef"
|
||||||
|
|
||||||
|
# Build iOS application
|
||||||
|
echo "Building iOS application with arguments: --$buildType --build-name=$buildName --build-number=$buildNumber"
|
||||||
|
flutter build ios --"$buildType" --build-name="$buildName" --build-number="$buildNumber"
|
||||||
@@ -10,7 +10,7 @@ import '../services/busylight_service.dart';
|
|||||||
const _kHostKey = 'busylight_host';
|
const _kHostKey = 'busylight_host';
|
||||||
const _kDefaultHost = 'http://igox-busylight.local';
|
const _kDefaultHost = 'http://igox-busylight.local';
|
||||||
const _kPollIntervalKey = 'busylight_poll_interval';
|
const _kPollIntervalKey = 'busylight_poll_interval';
|
||||||
const _kDefaultPollInterval = 5; // seconds
|
const _kDefaultPollInterval = 1.0; // seconds
|
||||||
|
|
||||||
final sharedPreferencesProvider = FutureProvider<SharedPreferences>(
|
final sharedPreferencesProvider = FutureProvider<SharedPreferences>(
|
||||||
(_) => SharedPreferences.getInstance(),
|
(_) => SharedPreferences.getInstance(),
|
||||||
@@ -21,9 +21,9 @@ final deviceHostProvider = StateProvider<String>((ref) {
|
|||||||
return prefs?.getString(_kHostKey) ?? _kDefaultHost;
|
return prefs?.getString(_kHostKey) ?? _kDefaultHost;
|
||||||
});
|
});
|
||||||
|
|
||||||
final pollIntervalProvider = StateProvider<int>((ref) {
|
final pollIntervalProvider = StateProvider<double>((ref) {
|
||||||
final prefs = ref.watch(sharedPreferencesProvider).valueOrNull;
|
final prefs = ref.watch(sharedPreferencesProvider).valueOrNull;
|
||||||
return prefs?.getInt(_kPollIntervalKey) ?? _kDefaultPollInterval;
|
return prefs?.getDouble(_kPollIntervalKey) ?? _kDefaultPollInterval.toDouble();
|
||||||
});
|
});
|
||||||
|
|
||||||
// ── Service ──────────────────────────────────────────────────────────────────
|
// ── Service ──────────────────────────────────────────────────────────────────
|
||||||
@@ -149,11 +149,6 @@ final colorProvider = StateNotifierProvider<ColorNotifier, BusylightColor>(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// ── Connection lost indicator ─────────────────────────────────────────────────
|
|
||||||
// Set to true by the polling notifier when a poll fails, false on success.
|
|
||||||
|
|
||||||
final connectionLostProvider = StateProvider<bool>((_) => false);
|
|
||||||
|
|
||||||
// ── Background polling ────────────────────────────────────────────────────────
|
// ── Background polling ────────────────────────────────────────────────────────
|
||||||
// Periodically pulls status + color from the device and silently updates state.
|
// Periodically pulls status + color from the device and silently updates state.
|
||||||
|
|
||||||
@@ -166,10 +161,11 @@ class PollingNotifier extends StateNotifier<void> {
|
|||||||
Timer? _timer;
|
Timer? _timer;
|
||||||
|
|
||||||
void _start() {
|
void _start() {
|
||||||
final interval = _ref.read(pollIntervalProvider);
|
final intervalSeconds = _ref.read(pollIntervalProvider);
|
||||||
|
final intervalMillis = (intervalSeconds * 1000).toInt();
|
||||||
_timer?.cancel();
|
_timer?.cancel();
|
||||||
if (interval <= 0) return;
|
if (intervalMillis <= 0) return;
|
||||||
_timer = Timer.periodic(Duration(seconds: interval), (_) => _poll());
|
_timer = Timer.periodic(Duration(milliseconds: intervalMillis), (_) => _poll());
|
||||||
}
|
}
|
||||||
|
|
||||||
void restart() => _start();
|
void restart() => _start();
|
||||||
@@ -186,11 +182,8 @@ class PollingNotifier extends StateNotifier<void> {
|
|||||||
_ref.read(busylightStatusProvider.notifier).setLocalStatus(status);
|
_ref.read(busylightStatusProvider.notifier).setLocalStatus(status);
|
||||||
_ref.read(colorProvider.notifier).silentSet(color);
|
_ref.read(colorProvider.notifier).silentSet(color);
|
||||||
_ref.read(brightnessProvider.notifier).silentSet(color.brightness);
|
_ref.read(brightnessProvider.notifier).silentSet(color.brightness);
|
||||||
// Connection restored — clear the lost flag
|
|
||||||
_ref.read(connectionLostProvider.notifier).state = false;
|
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
// Signal connectivity issue to the UI
|
// Silently ignore poll errors — connection issues are shown on manual refresh
|
||||||
_ref.read(connectionLostProvider.notifier).state = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -118,11 +118,10 @@ class _BodyState extends ConsumerState<_Body> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final statusAsync = ref.watch(busylightStatusProvider);
|
final statusAsync = ref.watch(busylightStatusProvider);
|
||||||
final brightness = ref.watch(brightnessProvider);
|
final brightness = ref.watch(brightnessProvider);
|
||||||
final color = ref.watch(colorProvider);
|
final color = ref.watch(colorProvider);
|
||||||
final presets = ref.watch(presetsProvider);
|
final presets = ref.watch(presetsProvider);
|
||||||
final connectionLost = ref.watch(connectionLostProvider);
|
|
||||||
|
|
||||||
final status = statusAsync.valueOrNull ?? BusylightStatus.off;
|
final status = statusAsync.valueOrNull ?? BusylightStatus.off;
|
||||||
final displayColor = _statusColor(status, color);
|
final displayColor = _statusColor(status, color);
|
||||||
@@ -130,7 +129,7 @@ class _BodyState extends ConsumerState<_Body> {
|
|||||||
return ListView(
|
return ListView(
|
||||||
padding: const EdgeInsets.all(24),
|
padding: const EdgeInsets.all(24),
|
||||||
children: [
|
children: [
|
||||||
// Live color preview dot — shows wifi-off icon when connection lost
|
// Live color preview dot
|
||||||
Center(
|
Center(
|
||||||
child: AnimatedContainer(
|
child: AnimatedContainer(
|
||||||
duration: const Duration(milliseconds: 400),
|
duration: const Duration(milliseconds: 400),
|
||||||
@@ -138,12 +137,10 @@ class _BodyState extends ConsumerState<_Body> {
|
|||||||
height: 100,
|
height: 100,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
color: connectionLost
|
color: status == BusylightStatus.off
|
||||||
? Colors.grey.shade900
|
? Colors.grey.shade900
|
||||||
: status == BusylightStatus.off
|
: displayColor.withOpacity(brightness),
|
||||||
? Colors.grey.shade900
|
boxShadow: status != BusylightStatus.off
|
||||||
: displayColor.withOpacity(brightness),
|
|
||||||
boxShadow: (!connectionLost && status != BusylightStatus.off)
|
|
||||||
? [BoxShadow(
|
? [BoxShadow(
|
||||||
color: displayColor.withOpacity(0.5 * brightness),
|
color: displayColor.withOpacity(0.5 * brightness),
|
||||||
blurRadius: 40,
|
blurRadius: 40,
|
||||||
@@ -151,20 +148,13 @@ class _BodyState extends ConsumerState<_Body> {
|
|||||||
)]
|
)]
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
child: connectionLost
|
|
||||||
? const Icon(Icons.wifi_off, color: Colors.grey, size: 36)
|
|
||||||
: null,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
Center(
|
Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
connectionLost ? 'NO CONNECTION' : status.label.toUpperCase(),
|
status.label.toUpperCase(),
|
||||||
style: TextStyle(
|
style: const TextStyle(color: Colors.grey, letterSpacing: 2, fontSize: 13),
|
||||||
color: connectionLost ? Colors.red.shade700 : Colors.grey,
|
|
||||||
letterSpacing: 2,
|
|
||||||
fontSize: 13,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 36),
|
const SizedBox(height: 36),
|
||||||
@@ -187,11 +177,9 @@ class _BodyState extends ConsumerState<_Body> {
|
|||||||
BusylightStatus.off,
|
BusylightStatus.off,
|
||||||
].map((s) => StatusButton(
|
].map((s) => StatusButton(
|
||||||
status: s,
|
status: s,
|
||||||
isActive: !connectionLost && status == s,
|
isActive: status == s,
|
||||||
isPending: _pendingStatus == s,
|
isPending: _pendingStatus == s,
|
||||||
onTap: (!connectionLost && _pendingStatus == null)
|
onTap: _pendingStatus == null ? () => _setStatus(s) : () {},
|
||||||
? () => _setStatus(s)
|
|
||||||
: () {},
|
|
||||||
)).toList(),
|
)).toList(),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 32),
|
const SizedBox(height: 32),
|
||||||
@@ -200,7 +188,7 @@ class _BodyState extends ConsumerState<_Body> {
|
|||||||
_PresetsScroller(
|
_PresetsScroller(
|
||||||
presets: presets,
|
presets: presets,
|
||||||
pendingPresetId: _pendingPresetId,
|
pendingPresetId: _pendingPresetId,
|
||||||
onPresetTap: (!connectionLost && _pendingStatus == null && _pendingPresetId == null)
|
onPresetTap: (_pendingStatus == null && _pendingPresetId == null)
|
||||||
? _applyPreset
|
? _applyPreset
|
||||||
: (_) {},
|
: (_) {},
|
||||||
onPresetDelete: (preset) => ref.read(presetsProvider.notifier).remove(preset.id),
|
onPresetDelete: (preset) => ref.read(presetsProvider.notifier).remove(preset.id),
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class SettingsScreen extends ConsumerStatefulWidget {
|
|||||||
|
|
||||||
class _SettingsScreenState extends ConsumerState<SettingsScreen> {
|
class _SettingsScreenState extends ConsumerState<SettingsScreen> {
|
||||||
late TextEditingController _hostController;
|
late TextEditingController _hostController;
|
||||||
late int _pollInterval;
|
late double _pollInterval;
|
||||||
bool _startWithSession = false;
|
bool _startWithSession = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -48,7 +48,7 @@ class _SettingsScreenState extends ConsumerState<SettingsScreen> {
|
|||||||
|
|
||||||
final prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
await prefs.setString('busylight_host', host);
|
await prefs.setString('busylight_host', host);
|
||||||
await prefs.setInt('busylight_poll_interval', _pollInterval);
|
await prefs.setDouble('busylight_poll_interval', _pollInterval);
|
||||||
|
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
@@ -58,10 +58,10 @@ class _SettingsScreenState extends ConsumerState<SettingsScreen> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String _intervalLabel(int seconds) {
|
String _intervalLabel(double seconds) {
|
||||||
if (seconds == 0) return 'Off';
|
if (seconds == 0.0) return 'Off';
|
||||||
if (seconds < 60) return '${seconds}s';
|
if (seconds < 2.0) return '${seconds}s';
|
||||||
return '${seconds ~/ 60}m';
|
return '${ (seconds)}s';
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -124,21 +124,21 @@ class _SettingsScreenState extends ConsumerState<SettingsScreen> {
|
|||||||
overlayColor: Colors.amber.withOpacity(0.2),
|
overlayColor: Colors.amber.withOpacity(0.2),
|
||||||
),
|
),
|
||||||
child: Slider(
|
child: Slider(
|
||||||
value: _pollInterval.toDouble(),
|
value: _pollInterval,
|
||||||
min: 0,
|
min: 0.0,
|
||||||
max: 60,
|
max: 2.0,
|
||||||
divisions: 12,
|
divisions: 4,
|
||||||
onChanged: (v) => setState(() => _pollInterval = v.round()),
|
onChanged: (v) => setState(() => _pollInterval = v),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text('Off', style: TextStyle(color: Colors.grey.shade600, fontSize: 11)),
|
Text('Off', style: TextStyle(color: Colors.grey.shade600, fontSize: 11)),
|
||||||
Text('5s', style: TextStyle(color: Colors.grey.shade600, fontSize: 11)),
|
Text('0.5s', style: TextStyle(color: Colors.grey.shade600, fontSize: 11)),
|
||||||
Text('10s', style: TextStyle(color: Colors.grey.shade600, fontSize: 11)),
|
Text('1s', style: TextStyle(color: Colors.grey.shade600, fontSize: 11)),
|
||||||
Text('30s', style: TextStyle(color: Colors.grey.shade600, fontSize: 11)),
|
Text('1.5s', style: TextStyle(color: Colors.grey.shade600, fontSize: 11)),
|
||||||
Text('1m', style: TextStyle(color: Colors.grey.shade600, fontSize: 11)),
|
Text('2s', style: TextStyle(color: Colors.grey.shade600, fontSize: 11)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 6),
|
const SizedBox(height: 6),
|
||||||
|
|||||||
Executable
+60
@@ -0,0 +1,60 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Default values
|
||||||
|
buildType="release"
|
||||||
|
buildName="0.0.0"
|
||||||
|
buildsRef="builds.json"
|
||||||
|
|
||||||
|
# Help message
|
||||||
|
show_help() {
|
||||||
|
echo "Usage: $0 [-t buildType] [-n buildName]"
|
||||||
|
echo "Builds a Flutter macOS application with versioning support."
|
||||||
|
echo ""
|
||||||
|
echo "Options:"
|
||||||
|
echo " -t, --buildType Build type (release or debug). Default: release"
|
||||||
|
echo " -n, --buildName Build name (version). Default: 0.0.0"
|
||||||
|
echo " -h, --help Show this help message"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Parse command-line arguments
|
||||||
|
while [[ "$#" -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
-t|--buildType) buildType="$2"; shift ;;
|
||||||
|
-n|--buildName) buildName="$2"; shift ;;
|
||||||
|
-h|--help) show_help ;;
|
||||||
|
*) echo "Unknown parameter: $1"; show_help; exit 1 ;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
# Check if builds.json exists
|
||||||
|
if [ ! -f "$buildsRef" ]; then
|
||||||
|
echo "File created: $buildsRef"
|
||||||
|
echo "{\"$buildName\": 0}" > "$buildsRef"
|
||||||
|
else
|
||||||
|
echo "File already exists: $buildsRef"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Read the JSON file
|
||||||
|
buildsMap=$(cat "$buildsRef")
|
||||||
|
|
||||||
|
# Check if buildName exists in the JSON
|
||||||
|
if jq -e --arg key "$buildName" 'has($key)' <<< "$buildsMap" > /dev/null; then
|
||||||
|
echo "Build exists: $buildName"
|
||||||
|
buildNumber=$(jq --arg key "$buildName" '.[$key]' <<< "$buildsMap")
|
||||||
|
buildNumber=$((buildNumber + 1))
|
||||||
|
echo "Next build number for $buildName: $buildNumber"
|
||||||
|
buildsMap=$(jq --arg key "$buildName" --argjson value "$buildNumber" '.[$key] = $value' <<< "$buildsMap")
|
||||||
|
else
|
||||||
|
echo "New build: $buildName, starting at build number: 1"
|
||||||
|
buildNumber=1
|
||||||
|
buildsMap=$(jq --arg key "$buildName" --argjson value "$buildNumber" '.[$key] = $value' <<< "$buildsMap")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Save the updated JSON back to the file
|
||||||
|
echo "$buildsMap" > "$buildsRef"
|
||||||
|
|
||||||
|
# Build macOS application
|
||||||
|
echo "Building macOS application with arguments: --$buildType --build-name=$buildName --build-number=$buildNumber"
|
||||||
|
flutter build macos --"$buildType" --build-name="$buildName" --build-number="$buildNumber"
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Builds a Flutter Windows installer with versioning support.
|
||||||
|
|
||||||
|
.DESCRIPTION
|
||||||
|
This script builds a Flutter Windows application and creates an installer using Inno Setup.
|
||||||
|
|
||||||
|
.PARAMETER buildType
|
||||||
|
The build type (release or debug). Default is "release".
|
||||||
|
|
||||||
|
.PARAMETER buildName
|
||||||
|
The build name (version). Default is "0.0.0".
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
.\build-windows-installer.ps1 -buildType debug -buildName 1.0.0
|
||||||
|
Builds a debug Windows application with version 1.0.0.
|
||||||
|
#>
|
||||||
|
|
||||||
|
[CmdletBinding()]
|
||||||
|
param (
|
||||||
|
[string]$buildType = "release", # Default value is "release"
|
||||||
|
[string]$buildName = "0.0.0" # Default value is "0.0.0"
|
||||||
|
)
|
||||||
|
|
||||||
|
$buildNumber = "$(Get-Date -Format 'yyyyMMddHHmmss')"
|
||||||
|
|
||||||
|
# Define the file path and the new version value
|
||||||
|
$issTplFile = "./busylight-buddy-windows-installer-builder.iss.tpl"
|
||||||
|
$issFile = "./busylight-buddy-windows-installer-builder.iss"
|
||||||
|
|
||||||
|
cd $PSScriptRoot
|
||||||
|
|
||||||
|
# Build an array for arguments
|
||||||
|
$flutterArgs = @(
|
||||||
|
"--$buildType",
|
||||||
|
"--build-name=$buildName",
|
||||||
|
"--build-number=$buildNumber"
|
||||||
|
)
|
||||||
|
|
||||||
|
Write-Output "Building Windows application with arguments: $($flutterArgs -join ' ')"
|
||||||
|
|
||||||
|
# Build the Windows application using Flutter
|
||||||
|
flutter build windows @flutterArgs
|
||||||
|
|
||||||
|
# Build the Windows installer using Inno Setup Compiler (ISCC.exe)
|
||||||
|
# Read the content of Inno Setup template file
|
||||||
|
$content = Get-Content -Path $issTplFile -Raw
|
||||||
|
|
||||||
|
# Replace the placeholder with the new version value
|
||||||
|
$updatedContent = $content -replace '%%MyAppVersion%%', $buildName
|
||||||
|
|
||||||
|
# Write the updated content back to Inno Setup file
|
||||||
|
$updatedContent | Set-Content -Path $issFile
|
||||||
|
|
||||||
|
ISCC.exe $issFile
|
||||||
+7
-7
@@ -3,7 +3,7 @@
|
|||||||
; Non-commercial use only
|
; Non-commercial use only
|
||||||
|
|
||||||
#define MyAppName "BusyLight Buddy"
|
#define MyAppName "BusyLight Buddy"
|
||||||
#define MyAppVersion "0.1"
|
#define MyAppVersion "%%MyAppVersion%%"
|
||||||
#define MyAppPublisher "iGoX"
|
#define MyAppPublisher "iGoX"
|
||||||
#define MyAppURL "https://github.com/igox/busylight-buddy"
|
#define MyAppURL "https://github.com/igox/busylight-buddy"
|
||||||
#define MyAppExeName "busylight_buddy.exe"
|
#define MyAppExeName "busylight_buddy.exe"
|
||||||
@@ -30,13 +30,13 @@ ArchitecturesAllowed=x64compatible
|
|||||||
; the 64-bit view of the registry.
|
; the 64-bit view of the registry.
|
||||||
ArchitecturesInstallIn64BitMode=x64compatible
|
ArchitecturesInstallIn64BitMode=x64compatible
|
||||||
DisableProgramGroupPage=yes
|
DisableProgramGroupPage=yes
|
||||||
LicenseFile="LICENSE"
|
LicenseFile="..\LICENSE"
|
||||||
; Uncomment the following line to run in non administrative install mode (install for current user only).
|
; Uncomment the following line to run in non administrative install mode (install for current user only).
|
||||||
;PrivilegesRequired=lowest
|
;PrivilegesRequired=lowest
|
||||||
PrivilegesRequiredOverridesAllowed=dialog
|
PrivilegesRequiredOverridesAllowed=dialog
|
||||||
OutputDir="windows\installer"
|
OutputDir="installer"
|
||||||
OutputBaseFilename=BusyLight-Buddy-Installer
|
OutputBaseFilename=BusyLight-Buddy-Installer
|
||||||
SetupIconFile="windows\runner\resources\app_icon.ico"
|
SetupIconFile="runner\resources\app_icon.ico"
|
||||||
SolidCompression=yes
|
SolidCompression=yes
|
||||||
WizardStyle=modern dynamic
|
WizardStyle=modern dynamic
|
||||||
|
|
||||||
@@ -47,9 +47,9 @@ Name: "english"; MessagesFile: "compiler:Default.isl"
|
|||||||
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
|
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
|
||||||
|
|
||||||
[Files]
|
[Files]
|
||||||
Source: "build\windows\x64\runner\Release\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
|
Source: "..\build\windows\x64\runner\Release\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
|
||||||
Source: "build\windows\x64\runner\Release\flutter_windows.dll"; DestDir: "{app}"; Flags: ignoreversion
|
Source: "..\build\windows\x64\runner\Release\flutter_windows.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||||
Source: "build\windows\x64\runner\Release\data\*"; DestDir: "{app}\data"; Flags: ignoreversion recursesubdirs createallsubdirs
|
Source: "..\build\windows\x64\runner\Release\data\*"; DestDir: "{app}\data"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||||
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
|
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
|
||||||
|
|
||||||
[Icons]
|
[Icons]
|
||||||
Reference in New Issue
Block a user