mirror of
https://github.com/localsend/localsend.git
synced 2026-06-23 04:10:07 +00:00
feat: finalize app icon status
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
- feat(macos): drag-and-drop files and text into menu bar icon (@ShlomoCode)
|
||||
- feat(macos): drag-and-drop text into the app icon (@ShlomoCode)
|
||||
- feat(macos): include LocalSend as a share target in the share menu (@ShlomoCode)
|
||||
- feat(macos): show error and success state in the app icon (@ShlomoCode, @Tienisto)
|
||||
|
||||
## 1.15.4 (2024-08-20)
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ class _ProgressPageState extends State<ProgressPage> with Refena {
|
||||
String? _remainingTime;
|
||||
List<FileDto> _files = []; // also contains declined files (files without token)
|
||||
Set<String> _selectedFiles = {};
|
||||
SessionStatus? _lastStatus;
|
||||
|
||||
// If [autoFinish] is enabled, we wait a few seconds before automatically closing the session.
|
||||
int _finishCounter = 3;
|
||||
@@ -169,12 +170,20 @@ class _ProgressPageState extends State<ProgressPage> with Refena {
|
||||
final currBytes = _files.fold<int>(
|
||||
0, (prev, curr) => prev + ((progressNotifier.getProgress(sessionId: widget.sessionId, fileId: curr.id) * curr.size).round()));
|
||||
|
||||
unawaited(TaskbarHelper.setProgressBar(currBytes, _totalBytes));
|
||||
|
||||
final receiveSession = ref.watch(serverProvider.select((s) => s?.session));
|
||||
final sendSession = ref.watch(sendProvider)[widget.sessionId];
|
||||
|
||||
final SessionStatus? status = receiveSession?.status ?? sendSession?.status;
|
||||
|
||||
if (status == SessionStatus.sending) {
|
||||
// ignore: discarded_futures
|
||||
TaskbarHelper.setProgressBar(currBytes, _totalBytes);
|
||||
} else if (status != _lastStatus) {
|
||||
_lastStatus = status;
|
||||
// ignore: discarded_futures
|
||||
TaskbarHelper.visualizeStatus(status);
|
||||
}
|
||||
|
||||
if (status == null) {
|
||||
return Scaffold(
|
||||
body: Container(),
|
||||
|
||||
@@ -22,7 +22,6 @@ import 'package:localsend_app/widget/responsive_list_view.dart';
|
||||
import 'package:refena_flutter/refena_flutter.dart';
|
||||
import 'package:routerino/routerino.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:windows_taskbar/windows_taskbar.dart';
|
||||
|
||||
class ReceivePage extends StatefulWidget {
|
||||
const ReceivePage({super.key});
|
||||
@@ -40,7 +39,13 @@ class _ReceivePageState extends State<ReceivePage> with Refena {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final vm = context.watch(receivePageControllerProvider);
|
||||
final vm = context.watch(receivePageControllerProvider, listener: (prev, next) {
|
||||
if (prev.status != next.status) {
|
||||
// ignore: discarded_futures
|
||||
TaskbarHelper.visualizeStatus(next.status);
|
||||
}
|
||||
});
|
||||
|
||||
if (vm.status == null && vm.message == null) {
|
||||
return const Scaffold(
|
||||
body: SizedBox(),
|
||||
@@ -48,11 +53,6 @@ class _ReceivePageState extends State<ReceivePage> with Refena {
|
||||
}
|
||||
|
||||
final senderFavoriteEntry = ref.watch(favoritesProvider.select((state) => state.findDevice(vm.sender)));
|
||||
if (vm.status == SessionStatus.canceledBySender) {
|
||||
unawaited(TaskbarHelper.setProgressBarMode(TaskbarProgressMode.error));
|
||||
} else {
|
||||
unawaited(TaskbarHelper.setProgressBarMode(TaskbarProgressMode.indeterminate));
|
||||
}
|
||||
|
||||
return WillPopScope(
|
||||
onWillPop: () async {
|
||||
|
||||
@@ -17,7 +17,6 @@ import 'package:localsend_app/widget/list_tile/device_list_tile.dart';
|
||||
import 'package:localsend_app/widget/responsive_list_view.dart';
|
||||
import 'package:refena_flutter/refena_flutter.dart';
|
||||
import 'package:routerino/routerino.dart';
|
||||
import 'package:windows_taskbar/windows_taskbar.dart';
|
||||
|
||||
class SendPage extends StatefulWidget {
|
||||
final bool showAppBar;
|
||||
@@ -61,7 +60,14 @@ class _SendPageState extends State<SendPage> with Refena {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final sendState = ref.watch(sendProvider)[widget.sessionId];
|
||||
final sendState = ref.watch(sendProvider.select((state) => state[widget.sessionId]), listener: (prev, next) {
|
||||
final prevStatus = prev[widget.sessionId]?.status;
|
||||
final nextStatus = next[widget.sessionId]?.status;
|
||||
if (prevStatus != nextStatus) {
|
||||
// ignore: discarded_futures
|
||||
TaskbarHelper.visualizeStatus(nextStatus);
|
||||
}
|
||||
});
|
||||
if (sendState == null && _myDevice == null && _targetDevice == null) {
|
||||
return Scaffold(
|
||||
body: Container(),
|
||||
@@ -72,12 +78,6 @@ class _SendPageState extends State<SendPage> with Refena {
|
||||
final targetFavoriteEntry = ref.watch(favoritesProvider.select((state) => state.findDevice(targetDevice)));
|
||||
final waiting = sendState?.status == SessionStatus.waiting;
|
||||
|
||||
if (sendState?.status == SessionStatus.declined || sendState?.status == SessionStatus.finishedWithErrors) {
|
||||
unawaited(TaskbarHelper.setProgressBarMode(TaskbarProgressMode.error));
|
||||
} else {
|
||||
unawaited(TaskbarHelper.setProgressBarMode(TaskbarProgressMode.indeterminate));
|
||||
}
|
||||
|
||||
return WillPopScope(
|
||||
onWillPop: () async {
|
||||
if (widget.closeSessionOnClose) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:common/model/session_status.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:localsend_app/util/native/macos_channel.dart';
|
||||
import 'package:localsend_app/util/native/platform_check.dart';
|
||||
@@ -25,6 +26,7 @@ class TaskbarHelper {
|
||||
if (_isWindows) {
|
||||
await WindowsTaskbar.setProgress(digestedProgress, digestedTotal);
|
||||
} else if (_isMacos) {
|
||||
print(progress);
|
||||
await updateDockProgress(progress / total);
|
||||
}
|
||||
} else {
|
||||
@@ -40,11 +42,45 @@ class TaskbarHelper {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> setTaskbarIcon(TaskbarIcon icon) async {
|
||||
static Future<void> setTaskbarIcon(TaskbarIcon icon) async {
|
||||
if (_isMacos) {
|
||||
await setDockIcon(icon);
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> visualizeStatus(SessionStatus? status) async {
|
||||
// macOS handling
|
||||
switch (status) {
|
||||
case SessionStatus.finished:
|
||||
await TaskbarHelper.setTaskbarIcon(TaskbarIcon.success);
|
||||
break;
|
||||
case SessionStatus.declined:
|
||||
case SessionStatus.recipientBusy:
|
||||
case SessionStatus.finishedWithErrors:
|
||||
case SessionStatus.canceledBySender:
|
||||
case SessionStatus.canceledByReceiver:
|
||||
await TaskbarHelper.setTaskbarIcon(TaskbarIcon.error);
|
||||
break;
|
||||
default:
|
||||
await TaskbarHelper.setTaskbarIcon(TaskbarIcon.regular);
|
||||
}
|
||||
|
||||
// Windows handling
|
||||
switch (status) {
|
||||
case SessionStatus.waiting:
|
||||
await TaskbarHelper.setProgressBarMode(TaskbarProgressMode.indeterminate);
|
||||
break;
|
||||
case SessionStatus.declined:
|
||||
case SessionStatus.recipientBusy:
|
||||
case SessionStatus.finishedWithErrors:
|
||||
case SessionStatus.canceledBySender:
|
||||
case SessionStatus.canceledByReceiver:
|
||||
await TaskbarHelper.setProgressBarMode(TaskbarProgressMode.error);
|
||||
break;
|
||||
default:
|
||||
await TaskbarHelper.setProgressBarMode(TaskbarProgressMode.normal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(int, int) _scaleRange(int progress, int total) {
|
||||
|
||||
@@ -3,7 +3,7 @@ import FlutterMacOS
|
||||
import Defaults
|
||||
import DockProgress
|
||||
|
||||
enum DockIcon {
|
||||
enum DockIcon: CaseIterable {
|
||||
case regular
|
||||
case error
|
||||
case success
|
||||
@@ -150,7 +150,8 @@ class AppDelegate: FlutterAppDelegate {
|
||||
DockProgress.progress = progress
|
||||
result(nil)
|
||||
case "setDockIcon":
|
||||
let newIcon = call.arguments as! DockIcon
|
||||
let newIconIndex = call.arguments as! Int
|
||||
let newIcon = DockIcon.allCases[newIconIndex]
|
||||
setDockIcon(icon: newIcon)
|
||||
default:
|
||||
result(FlutterMethodNotImplemented)
|
||||
|
||||
Reference in New Issue
Block a user