Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions lib/core/jnap/providers/polling_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -181,11 +181,12 @@ class PollingNotifier extends AsyncNotifier<CoreTransactionData> {
await ref.read(instantPrivacyProvider.notifier).fetch(statusOnly: true);

final loginType = ref.read(authProvider).value?.loginType;
logger.i('[Polling]: _additionalPolling loginType: $loginType');
if (loginType == LoginType.local) {
logger.i('[Polling]: checking active remote session');
await ref.read(remoteClientProvider.notifier).checkActiveSession();
}
// TODO: Disable remote assistance for now
// logger.i('[Polling]: _additionalPolling loginType: $loginType');
// if (loginType == LoginType.local) {
// logger.i('[Polling]: checking active remote session');
// await ref.read(remoteClientProvider.notifier).checkActiveSession();
// }
}

Future forcePolling() {
Expand Down
23 changes: 12 additions & 11 deletions lib/page/components/styled/top_bar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -146,17 +146,18 @@ class _TopBarState extends ConsumerState<TopBar> with DebugObserver {
_sessionExpireCounter(sessionInfo, expiredCountdown),
],
),
if (loginType == LoginType.local)
Padding(
padding: EdgeInsets.all(4.0),
child: AppIconButton.noPadding(
icon: Icons.support_agent,
color: Color(neutralTonal.get(100)),
onTap: () {
showRemoteAssistanceDialog(context, ref);
},
),
),
// TODO: Disable remote assistance for now
// if (loginType == LoginType.local)
// Padding(
// padding: EdgeInsets.all(4.0),
// child: AppIconButton.noPadding(
// icon: Icons.support_agent,
// color: Color(neutralTonal.get(100)),
// onTap: () {
// showRemoteAssistanceDialog(context, ref);
// },
// ),
// ),
const Padding(
padding: EdgeInsets.all(4.0),
child: GeneralSettingsWidget(),
Expand Down
18 changes: 12 additions & 6 deletions lib/page/instant_setup/pnp_admin_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -356,16 +356,21 @@ class _PnpAdminViewState extends ConsumerState<PnpAdminView> {
}
}, test: (error) => error is ExceptionInterruptAndExit).catchError(
(error, stackTrace) {
logger.e('[PnP]: Auto Master check unauthorized, redirect to login');
logger.e(
'[PnP]: Auto Master check unauthorized, redirect to login');
if (mounted) {
context.goNamed(RouteNamed.localLoginPassword);
}
}, test: (error) => error is ExceptionAutoMasterUnauthorized)
.catchError((error, stackTrace) {
},
test: (error) =>
error is ExceptionAutoMasterUnauthorized).catchError(
(error, stackTrace) {
logger.e('[PnP]: Auto Master polling failed, stay on error view');
// Do nothing - UI already showing error view with retry button
}, test: (error) => error is ExceptionAutoMasterPollingFailed)
.onError((error, stackTrace) {
},
test: (error) =>
error is ExceptionAutoMasterPollingFailed).onError(
(error, stackTrace) {
logger.e(
'[PnP]: ${_password == null ? 'There is no admin password, bring up the input view' : 'The given password is invalid'}',
);
Expand Down Expand Up @@ -590,7 +595,8 @@ class _PnpAdminViewState extends ConsumerState<PnpAdminView> {
}

// Polling exceeded max retry (timeout)
logger.w('[PnP]: Auto Master polling timeout, checking router connection');
logger
.w('[PnP]: Auto Master polling timeout, checking router connection');
try {
await pnp.testConnectionReconnected();
logger.i('[PnP]: Router connected after timeout, proceed to next step');
Expand Down
18 changes: 11 additions & 7 deletions lib/page/instant_setup/pnp_setup_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,9 @@ class _PnpSetupViewState extends ConsumerState<PnpSetupView>
stepperType: StepperType.horizontal,
// When showYourNetwork=true (except forceLogin), saving is handled by step's saveChanges, not onLastStep
// forceLogin + configured + !isPrePaired still needs onLastStep since no YourNetwork step
onLastStep: (_isUnconfigured || (!_forceLogin && !_isPrePaired)) ? null : _saveChanges,
onLastStep: (_isUnconfigured || (!_forceLogin && !_isPrePaired))
? null
: _saveChanges,
onStepChanged: ((index, step, controller) {
_currentStep = step;
_stepController = controller;
Expand Down Expand Up @@ -630,11 +632,12 @@ class _PnpSetupViewState extends ConsumerState<PnpSetupView>
if (showYourNetwork) {
setState(() {
_setupStep = _PnpSetupStep.config;
logger
.d('[PnP]: WiFi reconnected, showYourNetwork=true. Setup step = config');
logger.d(
'[PnP]: WiFi reconnected, showYourNetwork=true. Setup step = config');
});
} else {
logger.d('[PnP]: WiFi reconnected, showYourNetwork=false. Setup step = fwCheck');
logger.d(
'[PnP]: WiFi reconnected, showYourNetwork=false. Setup step = fwCheck');
_doFwUpdateCheck();
}
});
Expand Down Expand Up @@ -724,7 +727,8 @@ class _PnpSetupViewState extends ConsumerState<PnpSetupView>
logger.d('[PnP]: Auto Master failed, skipping timeout handling');
} else {
// Polling exceeded max retry (timeout)
logger.w('[PnP]: Auto Master polling timeout, checking router connection');
logger.w(
'[PnP]: Auto Master polling timeout, checking router connection');

if (autoMasterSaveAttempt >= _maxAutoMasterSaveAttempts) {
logger.e(
Expand Down Expand Up @@ -756,8 +760,8 @@ class _PnpSetupViewState extends ConsumerState<PnpSetupView>
// Edge case: Was Idle on entry but now Complete
if (statusOnEntry == AutoMasterStatus.idle &&
currentStatus == AutoMasterStatus.complete) {
logger
.w('[PnP]: Auto Master completed during PnP config - password changed');
logger.w(
'[PnP]: Auto Master completed during PnP config - password changed');
if (mounted) {
context.goNamed(RouteNamed.localLoginPassword);
}
Expand Down
99 changes: 50 additions & 49 deletions lib/page/nodes/providers/add_nodes_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -102,60 +102,61 @@ class AddNodesNotifier extends AutoDisposeNotifier<AddNodesState> {
}

bool onboardingProceed = false;
// For AutoOnboarding 2 service, there has no deviceOnboardingStatus
// only AutoOnboarding 3 service has deviceOnboardingStatus.
bool anyOnboarded = false;
var deviceOnboardingStatus = [];
// For AutoOnboarding 2 service, there has no deviceOnboardingStatus
// only AutoOnboarding 3 service has deviceOnboardingStatus.
bool anyOnboarded = false;
var deviceOnboardingStatus = [];

await for (final result in pollAutoOnboardingStatus()) {
logger.d('[AddNodes]: GetAutoOnboardingStatus result: $result');
// Update onboarding status
if (result is JNAPSuccess) {
if (result.output['autoOnboardingStatus'] == 'Onboarding') {
onboardingProceed = true;
await for (final result in pollAutoOnboardingStatus()) {
logger.d('[AddNodes]: GetAutoOnboardingStatus result: $result');
// Update onboarding status
if (result is JNAPSuccess) {
if (result.output['autoOnboardingStatus'] == 'Onboarding') {
onboardingProceed = true;
}
// Set deviceOnboardingStatus data
deviceOnboardingStatus =
result.output['deviceOnboardingStatus'] ?? [];
}
// Set deviceOnboardingStatus data
deviceOnboardingStatus = result.output['deviceOnboardingStatus'] ?? [];
}
}
// Get onboarded device data
anyOnboarded = List.from(deviceOnboardingStatus)
.any((element) => element['onboardingStatus'] == 'Onboarded');
// Get the MAC address list of these onboarded devices
List<String> onboardedMACList = [];
if (anyOnboarded) {
onboardedMACList = List.from(deviceOnboardingStatus)
.where((element) => element['onboardingStatus'] == 'Onboarded')
.map((e) => e['btMACAddress'] as String?)
.nonNulls
.toList();
}
logger.d(
'[AddNodes]: Number of onboarded MAC addresses = ${onboardedMACList.length}');
List<LinksysDevice> addedDevices = [];
List<LinksysDevice> childNodes = [];
List<BackHaulInfoData> backhaulInfoList = [];
state = state.copyWith(isLoading: true, loadingMessage: 'onboarding');
if (onboardingProceed && anyOnboarded) {
await for (final result in pollForNodesOnline(onboardedMACList)) {
childNodes =
result.where((element) => element.nodeType != null).toList();
addedDevices = result
.where(
(element) =>
element.nodeType == 'Slave' &&
(element.knownInterfaces?.any((knownInterface) =>
onboardedMACList
.contains(knownInterface.macAddress)) ??
false),
)
// Get onboarded device data
anyOnboarded = List.from(deviceOnboardingStatus)
.any((element) => element['onboardingStatus'] == 'Onboarded');
// Get the MAC address list of these onboarded devices
List<String> onboardedMACList = [];
if (anyOnboarded) {
onboardedMACList = List.from(deviceOnboardingStatus)
.where((element) => element['onboardingStatus'] == 'Onboarded')
.map((e) => e['btMACAddress'] as String?)
.nonNulls
.toList();
logger.d(
'[AddNodes]: [pollForNodesOnline] added devices: ${addedDevices.map((d) => d.toJson()).join(', ')}');
}
await for (final result in pollNodesBackhaulInfo(childNodes)) {
backhaulInfoList = result;
}
logger.d(
'[AddNodes]: Number of onboarded MAC addresses = ${onboardedMACList.length}');
List<LinksysDevice> addedDevices = [];
List<LinksysDevice> childNodes = [];
List<BackHaulInfoData> backhaulInfoList = [];
state = state.copyWith(isLoading: true, loadingMessage: 'onboarding');
if (onboardingProceed && anyOnboarded) {
await for (final result in pollForNodesOnline(onboardedMACList)) {
childNodes =
result.where((element) => element.nodeType != null).toList();
addedDevices = result
.where(
(element) =>
element.nodeType == 'Slave' &&
(element.knownInterfaces?.any((knownInterface) =>
onboardedMACList
.contains(knownInterface.macAddress)) ??
false),
)
.toList();
logger.d(
'[AddNodes]: [pollForNodesOnline] added devices: ${addedDevices.map((d) => d.toJson()).join(', ')}');
}
await for (final result in pollNodesBackhaulInfo(childNodes)) {
backhaulInfoList = result;
}
}
childNodes.sort((a, b) => a.isAuthority ? -1 : 1);
await polling.forcePolling();
Expand Down
3 changes: 2 additions & 1 deletion lib/page/nodes/views/add_nodes_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,8 @@ class _AddNodesViewState extends ConsumerState<AddNodesView> {
showFailedSnackBar(context, loc(context).generalError);
}
} catch (e) {
logger.e('[AddNodes]: Start auto onboarding failed with error: $e');
logger.e(
'[AddNodes]: Start auto onboarding failed with error: $e');
if (context.mounted) {
showFailedSnackBar(context, loc(context).generalError);
}
Expand Down
5 changes: 3 additions & 2 deletions lib/page/wifi_settings/views/widgets/wifi_name_field.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ class _WifiNameFieldState extends State<WifiNameField> {
@override
Widget build(BuildContext context) {
return AppTextField(
semanticLabel:
widget.semanticLabel.isEmpty ? 'wifi name' : '${widget.semanticLabel} wifi name',
semanticLabel: widget.semanticLabel.isEmpty
? 'wifi name'
: '${widget.semanticLabel} wifi name',
controller: widget.controller,
border: const OutlineInputBorder(),
onChanged: widget.onChanged,
Expand Down
20 changes: 8 additions & 12 deletions test/mocks/pnp_notifier_mocks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -388,22 +388,18 @@ class MockPnpNotifier extends _i2.Notifier<_i3.PnpState>
@override
_i9.Future<_i15.AutoMasterStatus?> checkAutoMasterStatus() =>
(super.noSuchMethod(
Invocation.method(#checkAutoMasterStatus, []),
returnValue: _i9.Future<_i15.AutoMasterStatus?>.value(),
returnValueForMissingStub:
_i9.Future<_i15.AutoMasterStatus?>.value(),
)
as _i9.Future<_i15.AutoMasterStatus?>);
Invocation.method(#checkAutoMasterStatus, []),
returnValue: _i9.Future<_i15.AutoMasterStatus?>.value(),
returnValueForMissingStub: _i9.Future<_i15.AutoMasterStatus?>.value(),
) as _i9.Future<_i15.AutoMasterStatus?>);

@override
_i9.Stream<_i15.AutoMasterStatus?> pollAutoMasterStatus() =>
(super.noSuchMethod(
Invocation.method(#pollAutoMasterStatus, []),
returnValue: _i9.Stream<_i15.AutoMasterStatus?>.empty(),
returnValueForMissingStub:
_i9.Stream<_i15.AutoMasterStatus?>.empty(),
)
as _i9.Stream<_i15.AutoMasterStatus?>);
Invocation.method(#pollAutoMasterStatus, []),
returnValue: _i9.Stream<_i15.AutoMasterStatus?>.empty(),
returnValueForMissingStub: _i9.Stream<_i15.AutoMasterStatus?>.empty(),
) as _i9.Stream<_i15.AutoMasterStatus?>);

@override
void setAutoMasterStatusOnEntry(_i15.AutoMasterStatus? status) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,8 @@ void main() async {
return AutoMasterStatus.running;
});
when(mockPnpNotifier.pollAutoMasterStatus()).thenAnswer((_) {
return Stream.fromFuture(
Future.delayed(const Duration(seconds: 5), () => AutoMasterStatus.running));
return Stream.fromFuture(Future.delayed(
const Duration(seconds: 5), () => AutoMasterStatus.running));
});

await tester.pumpWidget(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -670,7 +670,8 @@ void main() async {
);
await tester.pump(const Duration(seconds: 6));
// Trick - setState to trigger build
final state = tester.state<ConsumerState<PnpSetupView>>(find.byType(PnpSetupView));
final state =
tester.state<ConsumerState<PnpSetupView>>(find.byType(PnpSetupView));
state.setState(() {});
await tester.pumpAndSettle();
final ssidEditFinder = find.byType(TextField).first;
Expand All @@ -690,8 +691,7 @@ void main() async {
await tester.pump(const Duration(seconds: 2));
});

testLocalizations(
'Instant Setup - PnP: Auto Master connection error',
testLocalizations('Instant Setup - PnP: Auto Master connection error',
(tester, locale) async {
// First call returns idle (for initState), subsequent calls return running (for save)
var callCount = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -608,8 +608,7 @@ void main() {
await tester.pumpAndSettle();
});

testLocalizations(
'Incredible-WiFi - Advanced settings view - IPTV enabled',
testLocalizations('Incredible-WiFi - Advanced settings view - IPTV enabled',
(tester, locale) async {
when(mockWiFiAdvancedSettingsNotifier.build()).thenReturn(
WifiAdvancedSettingsState.fromMap(
Expand Down