Skip to content

Commit

Permalink
Merge pull request #1534 from atsign-foundation/1518-npt_atsign_bugs
Browse files Browse the repository at this point in the history
fix: npt ui fixes
  • Loading branch information
XavierChanth authored Nov 18, 2024
2 parents 7d0b994 + 9ac4cfc commit 5b09f7b
Show file tree
Hide file tree
Showing 14 changed files with 131 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:meta/meta.dart';
import 'package:npt_flutter/app.dart';
import 'package:npt_flutter/features/favorite/favorite.dart';
import 'package:npt_flutter/features/profile/profile.dart';
import 'package:npt_flutter/util/profile_status.dart';

part 'favorite.g.dart';

Expand Down Expand Up @@ -104,12 +105,13 @@ class FavoriteProfile extends Favorite<ProfileState> {
@override
String resolveStatus(ProfileState state) {
return switch (state) {
ProfileLoaded _ || ProfileFailedSave _ || ProfileFailedStart _ => '[Off]',
ProfileStarting _ => '[Starting]',
ProfileStarted _ => '[On - ${(state as ProfileLoadedState).profile.localPort}]',
ProfileStopping _ => '[Stopping]',
ProfileInitial _ || ProfileLoading _ => '[Loading]',
ProfileFailedLoad _ => '[Failed to load]'
ProfileLoaded _ || ProfileFailedSave _ => ProfileStatus.off.message,
ProfileStarting _ => ProfileStatus.starting.message,
ProfileStarted _ => '${ProfileStatus.on.message} - ${(state as ProfileLoadedState).profile.localPort}]',
ProfileStopping _ => ProfileStatus.stopping.message,
ProfileInitial _ || ProfileLoading _ => ProfileStatus.loading.message,
ProfileFailedStart _ => ProfileStatus.failedToStart.message,
ProfileFailedLoad _ => ProfileStatus.failedToLoad.message
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ class ProfileStatusIndicator extends StatelessWidget {
icon: PhosphorIcons.circle(PhosphorIconsStyle.fill),
);
}
if (state is ProfileFailedLoad) {
return StatusMessage(
tooltip: strings.profileFailedUnknownMessage,
status: strings.profileStatusFailedLoad,
color: Colors.red,
icon: PhosphorIcons.circle(PhosphorIconsStyle.fill),
);
}
if (state is ProfileStarting) {
return StatusMessage(
tooltip: state.status ?? strings.profileFailedUnknownMessage,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,12 @@ class ProfileLocalPortSelector extends StatelessWidget {
return SizedBox(
height: Sizes.p100,
child: TextFormField(
initialValue: state.toString(),
initialValue: state == 0 ? null : state.toString(),
autovalidateMode: AutovalidateMode.always,
validator: FormValidator.validateLocalPortField,
decoration: const InputDecoration(
decoration: InputDecoration(
hintText: '0',
hintStyle: Theme.of(context).textTheme.bodyLarge,
errorMaxLines: 2,
),
onChanged: (value) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import 'package:npt_flutter/features/onboarding/onboarding.dart';
import 'package:npt_flutter/features/profile/profile.dart';
import 'package:npt_flutter/features/profile_list/profile_list.dart';
import 'package:npt_flutter/routes.dart';
import 'package:npt_flutter/util/profile_status.dart';
import 'package:tray_manager/tray_manager.dart';
import 'package:window_manager/window_manager.dart';

Expand Down Expand Up @@ -136,8 +137,27 @@ class TrayCubit extends LoggingCubit<TrayState> {
? profileState.profile.displayName
: await fav.displayName;

var status = fav.status;
var label = '$displayName $status';
final status = fav.status;

final String statusIcon;
if (status == ProfileStatus.off.message) {
statusIcon = ProfileStatus.off.emoji;
} else if (status == ProfileStatus.starting.message) {
statusIcon = ProfileStatus.starting.emoji;
} else if (status?.contains(ProfileStatus.on.message) ?? false) {
statusIcon = ProfileStatus.on.emoji;
} else if (status == ProfileStatus.stopping.message) {
statusIcon = ProfileStatus.stopping.emoji;
} else if (status == ProfileStatus.loading.message) {
statusIcon = ProfileStatus.loading.emoji;
} else if (status == ProfileStatus.failedToStart.message) {
statusIcon = ProfileStatus.failedToStart.emoji;
} else if (status == ProfileStatus.failedToLoad.message) {
statusIcon = ProfileStatus.failedToLoad.emoji;
} else {
statusIcon = '';
}
var label = '$statusIcon $displayName';
return MenuItem(
label: label,
toolTip: status,
Expand Down
3 changes: 3 additions & 0 deletions packages/dart/npt_flutter/lib/localization/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
"exportLogs" : "Export Logs",
"faq" : "faq",
"feedback" : "Feedback",
"fileFormatInvalid" : "The document format is invalid. Please upload a valid file.",
"fileFormatInvalidDetails" : "The profiles section is missing or incorrectly formatted. Please check the document.",
"getStarted" : "Get Started",
"import" : "Import",
"json" : "JSON",
Expand Down Expand Up @@ -68,6 +70,7 @@
"profileName" : "Profile Name",
"profileNameDescription" : "This will be the name of you configurations",
"profileRunningActionDeniedMessage" : "Cannot perform this action while profile is running",
"profileStatusFailedLoad": "Failed to load",
"profileStatusFailedSave": "Failed to Save",
"profileStatusFailedStart": "Failed to start",
"profileStatusLoaded" : "Disconnected",
Expand Down
3 changes: 3 additions & 0 deletions packages/dart/npt_flutter/lib/localization/app_es.arb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
"failedToLoad" : "falló al cargar",
"faq" : "Preguntas frecuentes",
"feedback" : "Comentarios",
"fileFormatInvalid" : "El formato del documento no es válido. Por favor, suba un archivo válido.",
"fileFormatInvalidDetails" : "La sección de perfiles falta o está mal formateada. Por favor, revise el documento.",
"getStarted" : "Empezar",
"import" : "Importar",
"json" : "JSON",
Expand Down Expand Up @@ -69,6 +71,7 @@
"profileName" : "Nombre del perfil",
"profileNameDescription" : "Este será el nombre de sus configuraciones",
"profileRunningActionDeniedMessage" : "No se puede realizar esta acción mientras el perfil está en ejecución",
"profileStatusFailedLoad": "Error al cargar",
"profileStatusFailedSave": "Error al guardar",
"profileStatusFailedStart": "Error al iniciar",
"profileStatusLoaded" : "Desconectado",
Expand Down
3 changes: 3 additions & 0 deletions packages/dart/npt_flutter/lib/localization/app_pt.arb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
"failedToLoad" : "falha ao carregar",
"faq" : "faq",
"feedback" : "Feedback",
"fileFormatInvalid" : "O formato do documento é inválido. Por favor, carregue um arquivo válido.",
"fileFormatInvalidDetails" : "A seção de perfis está ausente ou formatada incorretamente. Por favor, verifique o documento.",
"getStarted" : "Começar",
"import" : "Importar",
"json" : "JSON",
Expand Down Expand Up @@ -69,6 +71,7 @@
"profileName" : "Nome do Perfil",
"profileNameDescription" : "Este será o nome das suas configurações",
"profileRunningActionDeniedMessage" : "Não é possível realizar esta ação enquanto o perfil está em execução",
"profileStatusFailedLoad": "Falha ao carregar",
"profileStatusFailedSave": "Falha ao salvar",
"profileStatusFailedStart": "Falha ao iniciar",
"profileStatusLoaded" : "Desconectado",
Expand Down
3 changes: 3 additions & 0 deletions packages/dart/npt_flutter/lib/localization/app_pt_BR.arb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
"failedToLoad" : "falha ao carregar",
"faq" : "faq",
"feedback" : "Feedback",
"fileFormatInvalid" : "O formato do documento é inválido. Por favor, carregue um arquivo válido.",
"fileFormatInvalidDetails" : "A seção de perfis está ausente ou formatada incorretamente. Por favor, verifique o documento.",
"getStarted" : "Começar",
"import" : "Importar",
"json" : "JSON",
Expand Down Expand Up @@ -69,6 +71,7 @@
"profileName" : "Nome do Perfil",
"profileNameDescription" : "Este será o nome das suas configurações",
"profileRunningActionDeniedMessage" : "Não é possível realizar esta ação enquanto o perfil está em execução",
"profileStatusFailedLoad": "Falha ao carregar",
"profileStatusFailedSave": "Falha ao salvar",
"profileStatusFailedStart": "Falha ao iniciar",
"profileStatusLoaded" : "Desconectado",
Expand Down
3 changes: 3 additions & 0 deletions packages/dart/npt_flutter/lib/localization/app_zh.arb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
"failedToLoad" : "加载失败",
"faq" : "常见问题",
"feedback" : "反馈",
"fileFormatInvalid" : "文档格式无效。请上传有效文件。",
"fileFormatInvalidDetails" : "配置文件部分缺失或格式不正确。请检查文档。",
"getStarted" : "开始",
"import" : "导入",
"json" : "JSON",
Expand Down Expand Up @@ -69,6 +71,7 @@
"profileName" : "配置文件名称",
"profileNameDescription" : "这将是您的配置名称",
"profileRunningActionDeniedMessage" : "配置文件运行时无法执行此操作",
"profileStatusFailedLoad": "加载失败",
"profileStatusFailedSave": "保存失败",
"profileStatusFailedStart": "启动失败",
"profileStatusLoaded" : "已断开连接",
Expand Down
3 changes: 3 additions & 0 deletions packages/dart/npt_flutter/lib/localization/app_zh_Hans_CH.arb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
"failedToLoad" : "加载失败",
"faq" : "常见问题",
"feedback" : "反馈",
"fileFormatInvalid" : "文档格式无效。请上传有效文件。",
"fileFormatInvalidDetails" : "配置文件部分缺失或格式不正确。请检查文档。",
"getStarted" : "开始",
"import" : "导入",
"json" : "JSON",
Expand Down Expand Up @@ -70,6 +72,7 @@
"profileName" : "配置文件名称",
"profileNameDescription" : "这将是您的配置名称",
"profileRunningActionDeniedMessage" : "配置文件运行时无法执行此操作",
"profileStatusFailedLoad": "加载失败",
"profileStatusFailedSave": "保存失败",
"profileStatusFailedStart": "启动失败",
"profileStatusLoaded" : "已断开",
Expand Down
3 changes: 3 additions & 0 deletions packages/dart/npt_flutter/lib/localization/app_zh_Hant_HK.arb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
"failedToLoad" : "加載失敗",
"faq" : "常見問題",
"feedback" : "反饋",
"fileFormatInvalid" : "文件格式無效。請上傳有效的文件。",
"fileFormatInvalidDetails" : "配置文件部分缺失或格式不正確。請檢查文件。",
"getStarted" : "開始",
"import" : "導入",
"json" : "JSON",
Expand Down Expand Up @@ -69,6 +71,7 @@
"profileName" : "配置文件名稱",
"profileNameDescription" : "這將是你的配置名稱",
"profileRunningActionDeniedMessage" : "配置文件運行時無法執行此操作",
"profileStatusFailedLoad": "加載失敗",
"profileStatusFailedSave": "保存失敗",
"profileStatusFailedStart": "啟動失敗",
"profileStatusLoaded" : "已斷開",
Expand Down
24 changes: 14 additions & 10 deletions packages/dart/npt_flutter/lib/util/export.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import 'dart:io';

import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:meta/meta.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:meta/meta.dart';
import 'package:npt_flutter/app.dart';
import 'package:npt_flutter/features/profile/models/profile.dart';
import 'package:npt_flutter/features/profile_list/profile_list.dart';
import 'package:npt_flutter/widgets/custom_snack_bar.dart';
import 'package:yaml/yaml.dart';
import 'package:yaml_writer/yaml_writer.dart';

Expand All @@ -22,15 +24,13 @@ enum ExportableProfileFiletype {
static ExportableProfileFiletype? fromExtension(String ext) =>
switch (ext) { "json" => json, "yaml" => yaml, _ => null };

static Iterable<String> get filetypes =>
ExportableProfileFiletype.values.map((e) => e.filetype);
static Iterable<String> get filetypes => ExportableProfileFiletype.values.map((e) => e.filetype);
}

class Export {
static const profilesKey = 'profiles';
@visibleForTesting
static Future<File?> pickAndCreateFile(
ExportableProfileFiletype filetype) async {
static Future<File?> pickAndCreateFile(ExportableProfileFiletype filetype) async {
String? outputFile = await FilePicker.platform.saveFile(
dialogTitle: 'Please select a file to export to:',
fileName: 'export.${filetype.filetype}',
Expand Down Expand Up @@ -81,7 +81,8 @@ class Export {
/// asynchronously
static void importProfiles() async {
try {
FilePickerResult? result = await FilePicker.platform.pickFiles();
FilePickerResult? result =
await FilePicker.platform.pickFiles(type: FileType.custom, allowedExtensions: ['json', 'yaml']);

if (result == null) {
return;
Expand All @@ -100,10 +101,15 @@ class Export {
/// Should return a [YamlMap] which implements [Map]
ExportableProfileFiletype.yaml => loadYaml(contents),
};
final strings = AppLocalizations.of(App.navState.currentContext!)!;

/// Type validation to ensure type safety
if (json is! Map) throw 'decoded $filetype document is not a Map';
if (json is! Map) {
CustomSnackBar.error(content: strings.fileFormatInvalid);
throw 'decoded $filetype document is not a Map';
}
if (json[profilesKey] is! List) {
CustomSnackBar.error(content: strings.fileFormatInvalidDetails, duration: const Duration(seconds: 3));
throw 'profiles is not a List in this document';
}

Expand All @@ -115,9 +121,7 @@ class Export {
.where((e) => e != null)
.cast<Profile>();

App.navState.currentContext
?.read<ProfileListBloc>()
.add(ProfileListAddEvent(profiles));
App.navState.currentContext?.read<ProfileListBloc>().add(ProfileListAddEvent(profiles));
} catch (e) {
App.log('Failed to import file: $e'.loggable);
}
Expand Down
2 changes: 1 addition & 1 deletion packages/dart/npt_flutter/lib/util/form_validator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class FormValidator {

var port = int.tryParse(value ?? '');
if (value?.isEmpty ?? true) {
return strings.validationErrorEmptyField;
return strings.validationErrorLocalPortField;
} else if (port == null || !(port >= 1024 && port <= 65535)) {
return strings.validationErrorLocalPortField;
}
Expand Down
53 changes: 53 additions & 0 deletions packages/dart/npt_flutter/lib/util/profile_status.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:npt_flutter/app.dart';

enum ProfileStatus {
off,
starting,
on,
stopping,
loading,
failedToStart,
failedToLoad,
}

extension ProfileStatusExtension on ProfileStatus {
String get message {
final strings = AppLocalizations.of(App.navState.currentContext!)!;
switch (this) {
case ProfileStatus.off:
return strings.profileStatusLoaded;
case ProfileStatus.starting:
return strings.profileStatusStarting;
case ProfileStatus.on:
return strings.profileStatusStarted;
case ProfileStatus.stopping:
return strings.profileStatusStopping;
case ProfileStatus.loading:
return strings.profileStatusLoading;
case ProfileStatus.failedToStart:
return strings.profileStatusFailedStart;
case ProfileStatus.failedToLoad:
return strings.profileStatusFailedLoad;
}
}

String get emoji {
switch (this) {
case ProfileStatus.off:
return '⚪';
case ProfileStatus.starting:
return '🟡';
case ProfileStatus.on:
return '🟢';
case ProfileStatus.stopping:
return '🟡';
case ProfileStatus.loading:
return '🟡';
case ProfileStatus.failedToStart:
return '🔴';
case ProfileStatus.failedToLoad:
return '🔴';
}
}
}

0 comments on commit 5b09f7b

Please sign in to comment.