Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
400dee57d4
|
|||
| b4ff5884b9 | |||
| beccfa05b3 |
+51
@@ -0,0 +1,51 @@
|
|||||||
|
# Miscellaneous
|
||||||
|
*.class
|
||||||
|
*.log
|
||||||
|
*.pyc
|
||||||
|
*.swp
|
||||||
|
.DS_Store
|
||||||
|
.atom/
|
||||||
|
.build/
|
||||||
|
.buildlog/
|
||||||
|
.history
|
||||||
|
.svn/
|
||||||
|
.swiftpm/
|
||||||
|
migrate_working_dir/
|
||||||
|
|
||||||
|
# IntelliJ related
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# The .vscode folder contains launch configuration and tasks you configure in
|
||||||
|
# VS Code which you may wish to be included in version control, so this line
|
||||||
|
# is commented out by default.
|
||||||
|
#.vscode/
|
||||||
|
|
||||||
|
# Flutter/Dart/Pub related
|
||||||
|
**/doc/api/
|
||||||
|
**/ios/Flutter/.last_build_id
|
||||||
|
.dart_tool/
|
||||||
|
.flutter-plugins-dependencies
|
||||||
|
.pub-cache/
|
||||||
|
.pub/
|
||||||
|
/build/
|
||||||
|
/coverage/
|
||||||
|
|
||||||
|
# Symbolication related
|
||||||
|
app.*.symbols
|
||||||
|
|
||||||
|
# Obfuscation related
|
||||||
|
app.*.map.json
|
||||||
|
|
||||||
|
# Android Studio will place build artifacts here
|
||||||
|
/android/app/debug
|
||||||
|
/android/app/profile
|
||||||
|
/android/app/release
|
||||||
|
|
||||||
|
.flutter-plugins-dependencies
|
||||||
|
android/key.properties
|
||||||
|
windows/installer/*
|
||||||
|
bugreport*
|
||||||
|
!downloads/*
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# This file tracks properties of this Flutter project.
|
||||||
|
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||||
|
#
|
||||||
|
# This file should be version controlled and should not be manually edited.
|
||||||
|
|
||||||
|
version:
|
||||||
|
revision: "2c9eb20739dfec95e2c74bd3dfa4601b0a8a36aa"
|
||||||
|
channel: "stable"
|
||||||
|
|
||||||
|
project_type: app
|
||||||
|
|
||||||
|
# Tracks metadata for the flutter migrate command
|
||||||
|
migration:
|
||||||
|
platforms:
|
||||||
|
- platform: root
|
||||||
|
create_revision: 2c9eb20739dfec95e2c74bd3dfa4601b0a8a36aa
|
||||||
|
base_revision: 2c9eb20739dfec95e2c74bd3dfa4601b0a8a36aa
|
||||||
|
- platform: windows
|
||||||
|
create_revision: 2c9eb20739dfec95e2c74bd3dfa4601b0a8a36aa
|
||||||
|
base_revision: 2c9eb20739dfec95e2c74bd3dfa4601b0a8a36aa
|
||||||
|
|
||||||
|
# User provided section
|
||||||
|
|
||||||
|
# List of Local paths (relative to this file) that should be
|
||||||
|
# ignored by the migrate tool.
|
||||||
|
#
|
||||||
|
# Files that are not part of the templates will be ignored by default.
|
||||||
|
unmanaged_files:
|
||||||
|
- 'lib/main.dart'
|
||||||
|
- 'ios/Runner.xcodeproj/project.pbxproj'
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# BusyLight Buddy
|
# BusyLight Buddy
|
||||||
|
|
||||||
Multiplatform Flutter app to control your DIY [BusyLight](https://github.com/igox/busylight) (ESP32 + MicroPython + Microdot).
|
Multiplatform Flutter app to control your DIY [BusyLight](https://code.igox.org/iGoX/busylight) (ESP32 + MicroPython + Microdot).
|
||||||
|
|
||||||
Supports **iOS**, **ipadOS**, **Android**, **macOS**, and **Windows**.
|
Supports **iOS**, **ipadOS**, **Android**, **macOS**, and **Windows**.
|
||||||
|
|
||||||
@@ -8,10 +8,10 @@ Supports **iOS**, **ipadOS**, **Android**, **macOS**, and **Windows**.
|
|||||||
|
|
||||||
## Downloads
|
## Downloads
|
||||||
|
|
||||||
[](https://github.com/igox/busylight-buddy/releases/download/v0.0.1/BusyLight-Buddy-Installer.exe)
|
[](https://code.igox.org/iGoX/busylight-buddy/releases/download/v0.0.1/BusyLight-Buddy-Installer.exe)
|
||||||
[](https://github.com/igox/busylight-buddy/releases/download/v0.0.1/org.igox.apps.android.busylight-buddy-release.apk)
|
[](https://code.igox.org/iGoX/busylight-buddy/releases/download/v0.0.1/org.igox.apps.android.busylight-buddy-release.apk)
|
||||||
|
|
||||||
Or browse all releases on the [Releases page](https://github.com/igox/busylight-buddy/releases).
|
Or browse all releases on the [Releases page](https://code.igox.org/iGoX/busylight-buddy/releases).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
<application
|
<application
|
||||||
android:label="BusyLight Buddy"
|
android:label="BusyLight Buddy"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
android:icon="@mipmap/ic_launcher">
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:usesCleartextTraffic="true">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
|
|||||||
@@ -149,6 +149,11 @@ 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.
|
||||||
|
|
||||||
@@ -181,8 +186,11 @@ 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 (_) {
|
||||||
// Silently ignore poll errors — connection issues are shown on manual refresh
|
// Signal connectivity issue to the UI
|
||||||
|
_ref.read(connectionLostProvider.notifier).state = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -122,6 +122,7 @@ class _BodyState extends ConsumerState<_Body> {
|
|||||||
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);
|
||||||
@@ -129,7 +130,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
|
// Live color preview dot — shows wifi-off icon when connection lost
|
||||||
Center(
|
Center(
|
||||||
child: AnimatedContainer(
|
child: AnimatedContainer(
|
||||||
duration: const Duration(milliseconds: 400),
|
duration: const Duration(milliseconds: 400),
|
||||||
@@ -137,10 +138,12 @@ class _BodyState extends ConsumerState<_Body> {
|
|||||||
height: 100,
|
height: 100,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
color: status == BusylightStatus.off
|
color: connectionLost
|
||||||
|
? Colors.grey.shade900
|
||||||
|
: status == BusylightStatus.off
|
||||||
? Colors.grey.shade900
|
? Colors.grey.shade900
|
||||||
: displayColor.withOpacity(brightness),
|
: displayColor.withOpacity(brightness),
|
||||||
boxShadow: status != BusylightStatus.off
|
boxShadow: (!connectionLost && status != BusylightStatus.off)
|
||||||
? [BoxShadow(
|
? [BoxShadow(
|
||||||
color: displayColor.withOpacity(0.5 * brightness),
|
color: displayColor.withOpacity(0.5 * brightness),
|
||||||
blurRadius: 40,
|
blurRadius: 40,
|
||||||
@@ -148,13 +151,20 @@ 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(
|
||||||
status.label.toUpperCase(),
|
connectionLost ? 'NO CONNECTION' : status.label.toUpperCase(),
|
||||||
style: const TextStyle(color: Colors.grey, letterSpacing: 2, fontSize: 13),
|
style: TextStyle(
|
||||||
|
color: connectionLost ? Colors.red.shade700 : Colors.grey,
|
||||||
|
letterSpacing: 2,
|
||||||
|
fontSize: 13,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 36),
|
const SizedBox(height: 36),
|
||||||
@@ -177,9 +187,11 @@ class _BodyState extends ConsumerState<_Body> {
|
|||||||
BusylightStatus.off,
|
BusylightStatus.off,
|
||||||
].map((s) => StatusButton(
|
].map((s) => StatusButton(
|
||||||
status: s,
|
status: s,
|
||||||
isActive: status == s,
|
isActive: !connectionLost && status == s,
|
||||||
isPending: _pendingStatus == s,
|
isPending: _pendingStatus == s,
|
||||||
onTap: _pendingStatus == null ? () => _setStatus(s) : () {},
|
onTap: (!connectionLost && _pendingStatus == null)
|
||||||
|
? () => _setStatus(s)
|
||||||
|
: () {},
|
||||||
)).toList(),
|
)).toList(),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 32),
|
const SizedBox(height: 32),
|
||||||
@@ -188,7 +200,7 @@ class _BodyState extends ConsumerState<_Body> {
|
|||||||
_PresetsScroller(
|
_PresetsScroller(
|
||||||
presets: presets,
|
presets: presets,
|
||||||
pendingPresetId: _pendingPresetId,
|
pendingPresetId: _pendingPresetId,
|
||||||
onPresetTap: (_pendingStatus == null && _pendingPresetId == null)
|
onPresetTap: (!connectionLost && _pendingStatus == null && _pendingPresetId == null)
|
||||||
? _applyPreset
|
? _applyPreset
|
||||||
: (_) {},
|
: (_) {},
|
||||||
onPresetDelete: (preset) => ref.read(presetsProvider.notifier).remove(preset.id),
|
onPresetDelete: (preset) => ref.read(presetsProvider.notifier).remove(preset.id),
|
||||||
|
|||||||
@@ -330,14 +330,10 @@
|
|||||||
inputFileListPaths = (
|
inputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||||
);
|
);
|
||||||
inputPaths = (
|
|
||||||
);
|
|
||||||
name = "[CP] Embed Pods Frameworks";
|
name = "[CP] Embed Pods Frameworks";
|
||||||
outputFileListPaths = (
|
outputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||||
);
|
);
|
||||||
outputPaths = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
||||||
|
|||||||
Reference in New Issue
Block a user