diff --git a/.github/workflows/github-actions-release-android.yml b/.github/workflows/github-actions-release-android.yml index 8dcb2f0..986205f 100644 --- a/.github/workflows/github-actions-release-android.yml +++ b/.github/workflows/github-actions-release-android.yml @@ -37,6 +37,6 @@ jobs: uses: ncipollo/release-action@v1 with: artifacts: 'build/app/outputs/apk/release/skyle_ik-android.zip' - tag: '2.1.0' + tag: '2.2.0' commit: main allowUpdates: true \ No newline at end of file diff --git a/.github/workflows/github-actions-release-ios.yml b/.github/workflows/github-actions-release-ios.yml index 297c802..282548e 100644 --- a/.github/workflows/github-actions-release-ios.yml +++ b/.github/workflows/github-actions-release-ios.yml @@ -34,6 +34,6 @@ jobs: uses: ncipollo/release-action@v1 with: artifacts: 'build/ios/iphoneos/skyle_ik-ios.zip' - tag: '2.1.0' + tag: '2.2.0' commit: main allowUpdates: true \ No newline at end of file diff --git a/.github/workflows/github-actions-release-linux.yml b/.github/workflows/github-actions-release-linux.yml index 2edda12..8416706 100644 --- a/.github/workflows/github-actions-release-linux.yml +++ b/.github/workflows/github-actions-release-linux.yml @@ -37,6 +37,6 @@ jobs: uses: ncipollo/release-action@v1 with: artifacts: 'build/linux/x64/release/bundle/skyle_ik-linux.zip' - tag: '2.1.0' + tag: '2.2.0' commit: main allowUpdates: true diff --git a/.github/workflows/github-actions-release-macos.yml b/.github/workflows/github-actions-release-macos.yml index 1b71f56..dfef181 100644 --- a/.github/workflows/github-actions-release-macos.yml +++ b/.github/workflows/github-actions-release-macos.yml @@ -33,6 +33,6 @@ jobs: uses: ncipollo/release-action@v1 with: artifacts: 'build/macos/Build/Products/Release/skyle_ik-macos/skyle_ik-macos.zip' - tag: '2.1.0' + tag: '2.2.0' commit: main allowUpdates: true \ No newline at end of file diff --git a/.github/workflows/github-actions-release-windows.yml b/.github/workflows/github-actions-release-windows.yml index 6cbf368..fc91169 100644 --- a/.github/workflows/github-actions-release-windows.yml +++ b/.github/workflows/github-actions-release-windows.yml @@ -32,6 +32,6 @@ jobs: uses: ncipollo/release-action@v1 with: artifacts: 'build/windows/x64/runner/Release/skyle_ik-windows.zip' - tag: '2.1.0' + tag: '2.2.0' commit: main allowUpdates: true \ No newline at end of file diff --git a/lib/config/app_state.dart b/lib/config/app_state.dart index 58ab3a8..eef4e7b 100644 --- a/lib/config/app_state.dart +++ b/lib/config/app_state.dart @@ -4,6 +4,7 @@ // Copyright © 2022 eyeV GmbH. All rights reserved. // +import 'package:async/async.dart'; import 'dart:async'; import 'package:flutter/material.dart'; @@ -18,6 +19,7 @@ import '../config/routes/main_router_delegate.dart'; import '../config/routes/route_state.dart'; import '../data/models/update/release_notes_response.dart'; import '../data/models/update/update_response.dart'; +import '../data/models/update/update_state.dart'; import '../data/repositories/update_repository_impl.dart'; import '../domain/repositories/update_repository.dart'; import 'local_settings_notifiers.dart'; @@ -51,7 +53,17 @@ class AppState { // Skyle Type stuff final skyleTypeProvider = StateProvider((ref) => SkyleType.skyleIntegrationKit); - final skyleVersionProvider = StateProvider((ref) => SkyleVersion.skyle3); + late final skyleVersionProvider = FutureProvider.autoDispose((ref) { + ref.keepAlive(); + final versions = ref.watch(versionsProvider); + if (versions.value is skyle.DataSuccess && versions.value != null && versions.value!.data != null) { + if (versions.value!.data!.skyleType.toString().startsWith("3")) { + return SkyleVersion.skyle3; + } else { + return SkyleVersion.skyle2; + } + } + }); // Skyle API oject final skyle.ET et = skyle.ET(); @@ -116,7 +128,10 @@ class AppState { if (connection == skyle.Connection.connected) { try { final versions = await ref.watch(AppState().versionsProvider.future); - if (versions is skyle.DataSuccess) ret = await repository.tryCheckForUpdate(versions.data!.firmware, versions.data!.serial, beta: beta); + final version = versions.data!.firmware; + final serial = versions.data!.serial; + + if (versions is skyle.DataSuccess) ret = await repository.tryCheckForUpdate(version, serial, beta: beta); } catch (e) { ret = skyle.DataFailed(e.toString()); } @@ -127,6 +142,79 @@ class AppState { return ret; }); + final uploadUpdateTriggerProvider = StateProvider((ref) { + return false; + }); + + final updatingStateProvider = StateProvider((ref) { + return UpdateState.none; + }); + + late final downloadUpdateProvider = StreamProvider.autoDispose((ref) async* { + ref.keepAlive(); + final connection = await ref.read(AppState().connectionProvider.future); + final repository = ref.read(AppState().updateRepositoryProvider); + final beta = ref.read(AppState().betaFirmwareProvider); + if (connection == skyle.Connection.connected) { + try { + final versions = await ref.read(AppState().versionsProvider.future); + ref.read(updatingStateProvider.notifier).state = UpdateState.downloading; + if (versions is skyle.DataSuccess) yield* repository.tryDownloadUpdate(versions.data!.firmware, versions.data!.serial, beta: beta); + } catch (e) { + // skyleLogger?.i(e.toString()); + } + } + }); + + late final uploadUpdateProvider = StreamProvider.autoDispose>((ref) async* { + ref.keepAlive(); + if (ref.watch(uploadUpdateTriggerProvider)) { + try { + ref.read(updatingStateProvider.notifier).state = UpdateState.uploading; + yield* ref.watch(AppState().updateRepositoryProvider).tryUpdate(); + } catch (e) { + // skyleLogger?.i(e.toString()); + yield skyle.DataFailed(e.toString()); + } + } + }); + + late final combinedDownloadingAndUploadingUpdateProvider = StreamProvider.autoDispose>((ref) async* { + final downloadStream = ref.watch(downloadUpdateProvider.stream); + final uploadStream = ref.watch(uploadUpdateProvider.stream); + yield* StreamGroup.merge([downloadStream, uploadStream]); + }); + + late final updatingProvider = StreamProvider.autoDispose>((ref) async* { + final connection = await ref.watch(AppState().connectionProvider.future); + if (connection == skyle.Connection.connecting) return; + if (ref.read(updatingStateProvider) == UpdateState.uploaded && connection == skyle.Connection.disconnected) { + yield const skyle.DataSuccess(UpdateState.updating); + ref.read(updatingStateProvider.notifier).state = UpdateState.updating; + return; + } + if (ref.read(updatingStateProvider) == UpdateState.updating && connection == skyle.Connection.connected) { + yield const skyle.DataSuccess(UpdateState.finished); + ref.read(updatingStateProvider.notifier).state = UpdateState.none; + return; + } + final updatingStateStream = ref.watch(combinedDownloadingAndUploadingUpdateProvider.stream); + await for (final updatingState in updatingStateStream) { + if (updatingState is skyle.DataSuccess) ref.read(updatingStateProvider.notifier).state = updatingState.data!; + yield updatingState; + } + }); + + late final newVersionProvider = FutureProvider.autoDispose>((ref) async { + final connection = await ref.watch(AppState().connectionProvider.future); + if (connection == skyle.Connection.connecting) return const skyle.DataFailed('Not connected'); + final repository = ref.read(AppState().updateRepositoryProvider); + final versions = await ref.watch(AppState().versionsProvider.future); + final beta = ref.read(AppState().betaFirmwareProvider); + if (versions is skyle.DataFailed) return skyle.DataFailed('${versions.error}'); + return repository.tryCheckForUpdate(versions.data!.firmware, versions.data!.serial, beta: beta); + }); + final releaseNotesProvider = FutureProvider.autoDispose.family?, bool>((ref, beta) async { ref.keepAlive(); final connection = await ref.watch(AppState().connectionProvider.future); diff --git a/lib/ui/main/beta_switch.dart b/lib/ui/main/beta_switch.dart index 482f682..5f0a4ad 100644 --- a/lib/ui/main/beta_switch.dart +++ b/lib/ui/main/beta_switch.dart @@ -11,7 +11,6 @@ import 'package:skyle_api/api.dart' as skyle; import '../../../config/theme/app_theme.dart'; -import '../../../util/responsive.dart'; import '../../config/app_state.dart'; import '../../config/routes/main_routes.dart'; import '../../data/models/update/update_state.dart'; @@ -19,7 +18,7 @@ import '../../data/models/update/update_state.dart'; class BetaSwitch extends ConsumerWidget { final AutoDisposeStreamProvider> downloadUpdateProvider; - const BetaSwitch({Key? key, required this.downloadUpdateProvider}) : super(key: key); + const BetaSwitch({super.key, required this.downloadUpdateProvider}); @override Widget build(BuildContext context, WidgetRef ref) { diff --git a/lib/ui/main/main_view.dart b/lib/ui/main/main_view.dart index f37ec6c..9e9f91b 100644 --- a/lib/ui/main/main_view.dart +++ b/lib/ui/main/main_view.dart @@ -13,6 +13,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:gaze_interactive/api.dart'; import 'package:minimize_app/minimize_app.dart'; import 'package:skyle_api/api.dart'; +import 'package:skyle_ik/ui/main/beta_switch.dart'; import 'package:universal_platform/universal_platform.dart'; import 'package:window_manager/window_manager.dart'; @@ -20,6 +21,7 @@ import '../../config/routes/main_routes.dart'; import '../../config/routes/routes.dart'; import '../../config/app_state.dart'; +import '../../data/models/update/update_state.dart'; import '../../util/responsive.dart'; import '../settings/gaze_speed_settings.dart'; import 'logo.dart'; @@ -29,14 +31,10 @@ import '../stream/stream_view.dart'; import '../calibration/calibration_points_view.dart'; class MainView extends ConsumerWidget { - MainView({Key? key}) : super(key: key); + const MainView({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { - final connection = ref.watch(AppState().connectionProvider).valueOrNull ?? Connection.disconnected; - final beta = ref.watch(AppState().betaFirmwareProvider); - final update = ref.watch(AppState().checkForUpdateProvider(beta)).valueOrNull ?? const DataFailed('error'); - final versions = ref.watch(AppState().versionsProvider).valueOrNull ?? const DataFailed('error'); return Stack( children: [ Container(color: Colors.black), @@ -48,79 +46,57 @@ class MainView extends ConsumerWidget { children: [ Flexible( flex: 2, - child: LogoTabbar(connection: connection), + child: Consumer( + builder: (context, localRef, child) { + final connection = localRef.watch(AppState().connectionProvider).valueOrNull ?? Connection.disconnected; + return LogoTabbar(connection: connection); + }, + ), ), - if (versions is DataSuccess) - Column( - children: [ - Padding( - padding: const EdgeInsets.all(5), - child: Material( - borderRadius: BorderRadius.circular(20), - child: InkWell( - borderRadius: BorderRadius.circular(20), - child: Padding( - padding: const EdgeInsets.all(8), - child: Text(versions.data!.firmware), + Consumer( + builder: (context, localRef, child) { + final versions = localRef.watch(AppState().versionsProvider).valueOrNull ?? const DataFailed('error'); + if (versions is DataSuccess) { + return Column( + children: [ + Padding( + padding: const EdgeInsets.all(5), + child: Material( + borderRadius: BorderRadius.circular(20), + child: InkWell( + borderRadius: BorderRadius.circular(20), + child: Padding( + padding: const EdgeInsets.all(8), + child: Text(versions.data!.firmware), + ), + onTap: () { + Clipboard.setData(ClipboardData(text: versions.data!.firmware)); + }, + ), ), - onTap: () { - Clipboard.setData(ClipboardData(text: versions.data!.firmware)); - }, ), - ), - ), - Padding( - padding: const EdgeInsets.all(5), - child: Material( - borderRadius: BorderRadius.circular(20), - child: InkWell( - borderRadius: BorderRadius.circular(20), - child: Padding( - padding: const EdgeInsets.all(8), - child: Text('${versions.data!.serial}'), + Padding( + padding: const EdgeInsets.all(5), + child: Material( + borderRadius: BorderRadius.circular(20), + child: InkWell( + borderRadius: BorderRadius.circular(20), + child: Padding( + padding: const EdgeInsets.all(8), + child: Text('${versions.data!.serial}'), + ), + onTap: () { + Clipboard.setData(ClipboardData(text: '${versions.data!.serial}')); + }, + ), ), - onTap: () { - Clipboard.setData(ClipboardData(text: '${versions.data!.serial}')); - }, - ), - ), - ), - ], - ), - Consumer( - builder: (context, loalRef, child) { - final skyleVersion = loalRef.watch(AppState().skyleVersionProvider); - return Column( - children: [ - ListTile( - title: const Text('Skyle 2'), - leading: Radio( - value: SkyleVersion.skyle2, - groupValue: skyleVersion, - onChanged: (SkyleVersion? value) async { - ref.read(AppState().skyleVersionProvider.notifier).state = value!; - await AppState().et.disconnect(); - await AppState().et.connect(grpcPort: value.version); - }, ), - ), - ListTile( - title: const Text('Sykle 3'), - leading: Radio( - value: SkyleVersion.skyle3, - groupValue: skyleVersion, - onChanged: (SkyleVersion? value) async { - ref.read(AppState().skyleVersionProvider.notifier).state = value!; - await AppState().et.disconnect(); - await AppState().et.connect(grpcPort: value.version); - }, - ), - ), - ], - ); + ], + ); + } + return Container(); }, ), - const Divider(), Consumer( builder: (context, loalRef, child) { final skyleType = loalRef.watch(AppState().skyleTypeProvider); @@ -155,16 +131,53 @@ class MainView extends ConsumerWidget { ); }, ), - badges.Badge( - position: badges.BadgePosition.topEnd(top: 20, end: 10), - badgeContent: const Padding( - padding: EdgeInsets.all(5), - child: Text('1'), - ), - showBadge: update is DataSuccess && update.data!.newupdate, - child: Container(), + Consumer( + builder: (context, localRef, child) { + final beta = localRef.watch(AppState().betaFirmwareProvider); + final update = localRef.watch(AppState().checkForUpdateProvider(beta)).valueOrNull ?? const DataFailed('error'); + return badges.Badge( + position: badges.BadgePosition.topEnd(top: 20, end: 10), + badgeContent: const Padding( + padding: EdgeInsets.all(5), + child: Text('1'), + ), + showBadge: update is DataSuccess && update.data!.newupdate, + child: Container(), + ); + }, ), const SearchForFirmwareUpdateButton(), + Consumer( + builder: (context, ref, child) { + final isBeta = ref.watch(AppState().isBetaProvider).valueOrNull ?? const DataSuccess(false); + final updatingState = ref.watch(AppState().updatingProvider).valueOrNull ?? const DataSuccess(UpdateState.none); + + final downloading = updatingState is DataSuccess && updatingState.data! == UpdateState.downloading || + (updatingState is DataLoading && ref.read(AppState().updatingStateProvider) == UpdateState.downloading); + final downloaded = updatingState is DataSuccess && updatingState.data! == UpdateState.downloaded; + final uploading = updatingState is DataSuccess && updatingState.data! == UpdateState.uploading || + (updatingState is DataLoading && ref.read(AppState().updatingStateProvider) == UpdateState.uploading); + final uploaded = updatingState is DataSuccess && updatingState.data! == UpdateState.uploaded; + final updating = updatingState is DataSuccess && updatingState.data! == UpdateState.updating; + final finished = updatingState is DataSuccess && updatingState.data! == UpdateState.finished; + final failed = updatingState is DataFailed; + if (isBeta is DataSuccess && isBeta.data! && !updating && !uploaded && !uploading && !finished) { + return Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Padding( + padding: EdgeInsets.only(left: 20), + child: Text('Beta?'), + ), + const Spacer(), + BetaSwitch(downloadUpdateProvider: AppState().downloadUpdateProvider), + ], + ); + } + return Container(); + }, + ), _ExitButton(), ], ), diff --git a/lib/ui/main/search_for_update_button.dart b/lib/ui/main/search_for_update_button.dart index e71008d..340be2a 100644 --- a/lib/ui/main/search_for_update_button.dart +++ b/lib/ui/main/search_for_update_button.dart @@ -4,7 +4,6 @@ // Copyright © 2022 eyeV GmbH. All rights reserved. // -import 'package:async/async.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -91,79 +90,6 @@ class SearchForFirmwareUpdateButton extends ConsumerWidget { } static Future showUpdateInstallDialog(BuildContext context) { - final uploadUpdateTriggerProvider = StateProvider((ref) { - return false; - }); - - final updatingStateProvider = StateProvider((ref) { - return UpdateState.none; - }); - - final downloadUpdateProvider = StreamProvider.autoDispose((ref) async* { - ref.keepAlive(); - final connection = await ref.read(AppState().connectionProvider.future); - final repository = ref.read(AppState().updateRepositoryProvider); - final beta = ref.read(AppState().betaFirmwareProvider); - if (connection == Connection.connected) { - try { - final versions = await ref.read(AppState().versionsProvider.future); - ref.read(updatingStateProvider.notifier).state = UpdateState.downloading; - if (versions is DataSuccess) yield* repository.tryDownloadUpdate(versions.data!.firmware, versions.data!.serial, beta: beta); - } catch (e) { - // skyleLogger?.i(e.toString()); - } - } - }); - - late final uploadUpdateProvider = StreamProvider.autoDispose>((ref) async* { - ref.keepAlive(); - if (ref.watch(uploadUpdateTriggerProvider)) { - try { - ref.read(updatingStateProvider.notifier).state = UpdateState.uploading; - yield* ref.watch(AppState().updateRepositoryProvider).tryUpdate(); - } catch (e) { - // skyleLogger?.i(e.toString()); - yield DataFailed(e.toString()); - } - } - }); - - late final combinedDownloadingAndUploadingUpdateProvider = StreamProvider.autoDispose>((ref) async* { - final downloadStream = ref.watch(downloadUpdateProvider.stream); - final uploadStream = ref.watch(uploadUpdateProvider.stream); - yield* StreamGroup.merge([downloadStream, uploadStream]); - }); - - late final updatingProvider = StreamProvider.autoDispose>((ref) async* { - final connection = await ref.watch(AppState().connectionProvider.future); - if (connection == Connection.connecting) return; - if (ref.read(updatingStateProvider) == UpdateState.uploaded && connection == Connection.disconnected) { - yield const DataSuccess(UpdateState.updating); - ref.read(updatingStateProvider.notifier).state = UpdateState.updating; - return; - } - if (ref.read(updatingStateProvider) == UpdateState.updating && connection == Connection.connected) { - yield const DataSuccess(UpdateState.finished); - ref.read(updatingStateProvider.notifier).state = UpdateState.none; - return; - } - final updatingStateStream = ref.watch(combinedDownloadingAndUploadingUpdateProvider.stream); - await for (final updatingState in updatingStateStream) { - if (updatingState is DataSuccess) ref.read(updatingStateProvider.notifier).state = updatingState.data!; - yield updatingState; - } - }); - - late final newVersionProvider = FutureProvider.autoDispose>((ref) async { - final connection = await ref.watch(AppState().connectionProvider.future); - if (connection == Connection.connecting) return const DataFailed('Not connected'); - final repository = ref.read(AppState().updateRepositoryProvider); - final versions = await ref.watch(AppState().versionsProvider.future); - final beta = ref.read(AppState().betaFirmwareProvider); - if (versions is DataFailed) return DataFailed('${versions.error}'); - return repository.tryCheckForUpdate(versions.data!.firmware, versions.data!.serial, beta: beta); - }); - Routes.dialog(); return showDialog( context: context, @@ -172,17 +98,16 @@ class SearchForFirmwareUpdateButton extends ConsumerWidget { builder: (context) { return Consumer( builder: (context, ref, child) { - // final isBeta = ref.watch(AppState().isBetaProvider).valueOrNull ?? const DataSuccess(false); final versions = ref.watch(AppState().versionsProvider).valueOrNull ?? const DataFailed('error'); - final newVersion = ref.watch(newVersionProvider).valueOrNull ?? const DataFailed('error'); + final newVersion = ref.watch(AppState().newVersionProvider).valueOrNull ?? const DataFailed('error'); - final updatingState = ref.watch(updatingProvider).valueOrNull ?? const DataSuccess(UpdateState.none); + final updatingState = ref.watch(AppState().updatingProvider).valueOrNull ?? const DataSuccess(UpdateState.none); final downloading = updatingState is DataSuccess && updatingState.data! == UpdateState.downloading || - (updatingState is DataLoading && ref.read(updatingStateProvider) == UpdateState.downloading); + (updatingState is DataLoading && ref.read(AppState().updatingStateProvider) == UpdateState.downloading); final downloaded = updatingState is DataSuccess && updatingState.data! == UpdateState.downloaded; final uploading = updatingState is DataSuccess && updatingState.data! == UpdateState.uploading || - (updatingState is DataLoading && ref.read(updatingStateProvider) == UpdateState.uploading); + (updatingState is DataLoading && ref.read(AppState().updatingStateProvider) == UpdateState.uploading); final uploaded = updatingState is DataSuccess && updatingState.data! == UpdateState.uploaded; final updating = updatingState is DataSuccess && updatingState.data! == UpdateState.updating; final finished = updatingState is DataSuccess && updatingState.data! == UpdateState.finished; @@ -206,7 +131,7 @@ class SearchForFirmwareUpdateButton extends ConsumerWidget { if (!finished) Expanded( flex: 3, - child: _text(updatingState, ref.read(updatingStateProvider) == UpdateState.uploading), + child: _text(updatingState, ref.read(AppState().updatingStateProvider) == UpdateState.uploading), ), const Spacer(), if (finished || failed) @@ -242,18 +167,8 @@ class SearchForFirmwareUpdateButton extends ConsumerWidget { ), if (downloading || downloaded) _DownloadUploadUpdate( - updatingProvider: updatingProvider, + updatingProvider: AppState().updatingProvider, ), - // if (isBeta is DataSuccess && isBeta.data! && !updating && !uploaded && !uploading && !finished) - // Row( - // crossAxisAlignment: CrossAxisAlignment.center, - // mainAxisAlignment: MainAxisAlignment.center, - // children: [ - // const Text('Receive beta updates?'), - // const Spacer(), - // BetaSwitch(downloadUpdateProvider: downloadUpdateProvider), - // ], - // ), const Spacer(), Padding( padding: Responsive.padding(context, const EdgeInsets.fromLTRB(0, 0, 0, 0)), @@ -300,7 +215,7 @@ class SearchForFirmwareUpdateButton extends ConsumerWidget { : downloaded ? () async { // Trigger Update - ref.read(uploadUpdateTriggerProvider.notifier).state = true; + ref.read(AppState().uploadUpdateTriggerProvider.notifier).state = true; } : null, ), diff --git a/lib/ui/stream/guided_stream_view.dart b/lib/ui/stream/guided_stream_view.dart index 723013f..4f2d754 100644 --- a/lib/ui/stream/guided_stream_view.dart +++ b/lib/ui/stream/guided_stream_view.dart @@ -67,35 +67,47 @@ class GuidedStreamView extends ConsumerWidget { // ), ), ), - AnimatedPositioned( - key: const Key('LeftEye'), - left: leftEye.x / AppState().et.resolution(skyleVersion.version).width * maxWidth - size / 2, - top: leftEye.y / AppState().et.resolution(skyleVersion.version).height * maxHeight - size / 2, - duration: const Duration(milliseconds: 30), - child: AnimatedContainer( - width: size, - height: size, - decoration: BoxDecoration( - color: Colors.white.withOpacity(opacity), //SkyleTheme.of(context).primaryColor, - shape: BoxShape.circle, - ), - duration: const Duration(milliseconds: 100), - ), + skyleVersion.when( + data: (value) => value != null + ? AnimatedPositioned( + key: const Key('LeftEye'), + left: leftEye.x / AppState().et.resolution(value.version).width * maxWidth - size / 2, + top: leftEye.y / AppState().et.resolution(value.version).height * maxHeight - size / 2, + duration: const Duration(milliseconds: 30), + child: AnimatedContainer( + width: size, + height: size, + decoration: BoxDecoration( + color: Colors.white.withOpacity(opacity), //SkyleTheme.of(context).primaryColor, + shape: BoxShape.circle, + ), + duration: const Duration(milliseconds: 100), + ), + ) + : Container(), + loading: () => Container(), + error: (_, __) => Container(), ), - AnimatedPositioned( - key: const Key('RightEye'), - left: rightEye.x / AppState().et.resolution(skyleVersion.version).width * maxWidth - size / 2, - top: rightEye.y / AppState().et.resolution(skyleVersion.version).height * maxHeight - size / 2, - duration: const Duration(milliseconds: 30), - child: AnimatedContainer( - width: size, - height: size, - decoration: BoxDecoration( - color: Colors.white.withOpacity(opacity), //SkyleTheme.of(context).primaryColor, - shape: BoxShape.circle, - ), - duration: const Duration(milliseconds: 150), - ), + skyleVersion.when( + data: (value) => value != null + ? AnimatedPositioned( + key: const Key('RightEye'), + left: rightEye.x / AppState().et.resolution(value!.version).width * maxWidth - size / 2, + top: rightEye.y / AppState().et.resolution(value.version).height * maxHeight - size / 2, + duration: const Duration(milliseconds: 30), + child: AnimatedContainer( + width: size, + height: size, + decoration: BoxDecoration( + color: Colors.white.withOpacity(opacity), //SkyleTheme.of(context).primaryColor, + shape: BoxShape.circle, + ), + duration: const Duration(milliseconds: 100), + ), + ) + : Container(), + loading: () => Container(), + error: (_, __) => Container(), ), Center( child: AnimatedOpacity( diff --git a/lib/ui/stream/stream_view.dart b/lib/ui/stream/stream_view.dart index e56ca8a..315fc01 100644 --- a/lib/ui/stream/stream_view.dart +++ b/lib/ui/stream/stream_view.dart @@ -55,34 +55,38 @@ class StreamView extends ConsumerWidget { Flexible( child: Container( padding: Responsive.padding(context, const EdgeInsets.fromLTRB(20, 0, 20, 20)), - child: LayoutBuilder( - builder: (context, constraints) { - var maxWidth = - constraints.maxHeight * AppState().et.resolution(skyleVersion.version).width / AppState().et.resolution(skyleVersion.version).height; - if (maxWidth > constraints.maxWidth) maxWidth = constraints.maxWidth; - var maxHeight = - constraints.maxWidth * AppState().et.resolution(skyleVersion.version).height / AppState().et.resolution(skyleVersion.version).width; - if (maxHeight > constraints.maxHeight) maxHeight = constraints.maxHeight; - return ConstrainedBox( - constraints: BoxConstraints(maxHeight: maxHeight, maxWidth: maxWidth), - // child: Stack( - // children: [ - // _mjpeg(context, maxWidth, maxWidth), - // GuidedStreamContainerView( - // et: et, - // maxWidth: maxWidth, - // maxHeight: maxHeight, - // ) - // ], - // ), - child: positioningType == PositioningType.guided - ? GuidedStreamContainerView( - maxWidth: maxWidth, - maxHeight: maxHeight, - ) - : _mjpeg(context, maxWidth, maxWidth), - ); - }, + child: skyleVersion.when( + data: (value) => value != null + ? LayoutBuilder( + builder: (context, constraints) { + var maxWidth = constraints.maxHeight * AppState().et.resolution(value.version).width / AppState().et.resolution(value.version).height; + if (maxWidth > constraints.maxWidth) maxWidth = constraints.maxWidth; + var maxHeight = constraints.maxWidth * AppState().et.resolution(value.version).height / AppState().et.resolution(value.version).width; + if (maxHeight > constraints.maxHeight) maxHeight = constraints.maxHeight; + return ConstrainedBox( + constraints: BoxConstraints(maxHeight: maxHeight, maxWidth: maxWidth), + // child: Stack( + // children: [ + // _mjpeg(context, maxWidth, maxWidth), + // GuidedStreamContainerView( + // et: et, + // maxWidth: maxWidth, + // maxHeight: maxHeight, + // ) + // ], + // ), + child: positioningType == PositioningType.guided + ? GuidedStreamContainerView( + maxWidth: maxWidth, + maxHeight: maxHeight, + ) + : _mjpeg(context, maxWidth, maxWidth, value), + ); + }, + ) + : Container(), + error: (error, stackTrace) => Text(error.toString()), + loading: () => const Center(child: CircularProgressIndicator()), ), ), ), @@ -90,31 +94,32 @@ class StreamView extends ConsumerWidget { ); } - Widget _mjpeg(BuildContext context, double width, double height) { + Widget _mjpeg(BuildContext context, double width, double height, SkyleVersion skyleVersion) { return ClipRRect( borderRadius: BorderRadius.circular(20), - child: const RawImageView(), - // MjpegView( - // width: width, - // height: height, - // fit: BoxFit.fill, - // error: (context, error) { - // return Column( - // mainAxisAlignment: MainAxisAlignment.center, - // children: [ - // Row( - // mainAxisAlignment: MainAxisAlignment.center, - // children: [ - // Icon( - // Icons.videocam_off, - // color: SkyleTheme.of(context).primaryColor, - // ), - // ], - // ), - // ], - // ); - // }, - // ), + child: skyleVersion == SkyleVersion.skyle3 + ? const RawImageView() + : MjpegView( + width: width, + height: height, + fit: BoxFit.fill, + error: (context, error) { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.videocam_off, + color: SkyleTheme.of(context).primaryColor, + ), + ], + ), + ], + ); + }, + ), ); } diff --git a/pubspec.lock b/pubspec.lock index 49adc55..0b79835 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -34,7 +34,7 @@ packages: source: hosted version: "2.5.0" async: - dependency: transitive + dependency: "direct main" description: name: async sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" diff --git a/pubspec.yaml b/pubspec.yaml index 04c0171..3b308fa 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -3,12 +3,13 @@ description: A simple example application to calibrate the Skyle eye-tracker. publish_to: 'none' -version: 2.1.0 +version: 2.2.0 environment: sdk: '>=2.18.0 <3.0.0' dependencies: + async: ^2.11.0 badges: ^3.0.2 bitmap: ^0.2.0