diff --git a/.gitignore b/.gitignore index 5942e1d..0881ef0 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,6 @@ app.*.map.json /android/app/profile /android/app/release pubspec.lock + +# AGP 8 écrit ses rapports ici malgré rootProject.buildDir = ../build +/android/build/ diff --git a/android/build.gradle b/android/build.gradle index b8bd72e..8b1ba08 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,21 +1,11 @@ -/*buildscript { - ext.kotlin_version = '2.0.10' - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:8.5.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath 'com.google.gms:google-services:4.3.15' - } -}*/ +// Les versions d'AGP et du plugin Kotlin sont déclarées dans settings.gradle. +// Un buildscript commenté les redéclarait ici : il a fait conclure deux fois à +// une config qui n'était pas celle appliquée. Supprimé plutôt que laissé mort. allprojects { repositories { google() - jcenter() + mavenCentral() } } @@ -23,16 +13,10 @@ rootProject.buildDir = '../build' subprojects { project.buildDir = "${rootProject.buildDir}/${project.name}" } -subprojects { - //project.evaluationDependsOn(':app') - project.configurations.all { - resolutionStrategy.eachDependency { details -> - if (details.requested.group == 'androidx.lifecycle') { - details.useVersion '2.4.0' // To fix mapbox issue.. - } - } - } -} +// Un resolutionStrategy forçait ici androidx.lifecycle à 2.4.0, commenté +// « To fix mapbox issue ». C'est devenu la cause du problème inverse : mapbox_maps_flutter +// 2.21.1 appelle setViewTreeLifecycleOwner, absent de 2.4.0, et sa compilation Kotlin +// échouait. mymuseum-visitapp utilise le même plugin sans ce forçage. Retiré le 2026-08-12. tasks.register("clean", Delete) { delete rootProject.buildDir diff --git a/android/gradle.properties b/android/gradle.properties index b535c78..91ce4d7 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,9 +1,8 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4096M android.useAndroidX=true -android.enableJetifier=true +android.enableJetifier=false android.enableR8=true SDK_REGISTRY_TOKEN=sk.eyJ1IjoidGZyYW5zb2xldCIsImEiOiJjbHRpcTF1d28wYmxmMmxwNjRleXpodGY0In0.qr-jo1vAb08bL3WRDEB4pw -android.bundle.enableUncompressedNativeLibs=false android.experimental.enable16kApk=true android.useNewNativePlugin=true # This builtInKotlin flag was added automatically by Flutter migrator diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 6b66533..9162f10 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip diff --git a/android/settings.gradle b/android/settings.gradle index 2e8e75d..6d891db 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -18,9 +18,9 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id 'com.android.application' version '7.2.0' apply false - id 'com.android.library' version '7.2.0' apply false - id 'org.jetbrains.kotlin.android' version '1.9.0' apply false + id 'com.android.application' version '8.9.1' apply false + id 'com.android.library' version '8.9.1' apply false + id 'org.jetbrains.kotlin.android' version '2.3.10' apply false id "com.google.gms.google-services" version "4.3.15" apply false id "com.google.firebase.crashlytics" version "2.9.9" apply false /*id "com.google.firebase:firebase-bom" version "32.7.0" diff --git a/lib/Components/Buttons/rounded_button.dart b/lib/Components/Buttons/rounded_button.dart index cf62882..df163e9 100644 --- a/lib/Components/Buttons/rounded_button.dart +++ b/lib/Components/Buttons/rounded_button.dart @@ -37,7 +37,7 @@ class RoundedButton extends StatelessWidget { backgroundColor: MaterialStateColor.resolveWith((states) => color!), shape: MaterialStateProperty.all( RoundedRectangleBorder( - borderRadius: BorderRadius.circular(tabletAppContext.configuration?.roundedValue?.toDouble() ?? 20.0), + borderRadius: BorderRadius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0), ) ) ), diff --git a/lib/Helpers/geo.dart b/lib/Helpers/geo.dart new file mode 100644 index 0000000..6609c9a --- /dev/null +++ b/lib/Helpers/geo.dart @@ -0,0 +1,46 @@ +import 'dart:math'; + +import 'package:manager_api_new/api.dart'; + +/// GeoPointDTO ne porte plus `latitude`/`longitude` depuis le passage à PostGIS : +/// la position vit dans `geometry.coordinates`, que `GeometryMapper` sérialise +/// côté serveur sous la forme `[X, Y]` — donc **[longitude, latitude]**, l'ordre +/// GeoJSON. C'est aussi ce que lit mymuseum-visitapp (`Models/agenda.dart`). +/// +/// ⚠️ Ne pas généraliser aux géométries de GuidedStep : celles-là sont écrites +/// par manager-app dans l'ordre inverse, `[lat, lng]` (cf. `visitapp-web/src/lib/geo.ts`). +extension GeoPointPosition on GeoPointDTO { + double? get lat => _coordinate(1); + + double? get lng => _coordinate(0); + + /// Clé numérique dérivée des coordonnées, utilisée par `geo_point_filter` pour + /// apparier un `TreeNode` et son GeoPoint (l'`id` du DTO ne convient pas : il est + /// réattribué à la volée à l'affichage). + /// + /// Formule reprise telle quelle de l'ancien code — représentation textuelle + /// tronquée à 10 caractères, points et signes retirés. Elle n'est pas persistée, + /// mais **les deux côtés de l'appariement doivent produire la même valeur** : elle + /// était dupliquée à quatre endroits, elle ne vit plus qu'ici. + int get coordinateKey { + String part(double? value) { + if (value == null) return '0'; + final text = value.toString(); + return text + .substring(0, min(text.length, 10)) + .replaceAll('.', '') + .replaceAll('-', ''); + } + + return int.parse(part(lat) + part(lng)); + } + + /// `coordinates` est typé `Object?` dans le client généré : sans ce narrowing, + /// tout calcul dessus part en `dynamic` et casse à la compilation. + double? _coordinate(int index) { + final coordinates = geometry?.coordinates; + if (coordinates is! List || coordinates.length <= index) return null; + final value = coordinates[index]; + return value is num ? value.toDouble() : null; + } +} diff --git a/lib/Models/tabletContext.dart b/lib/Models/tabletContext.dart index adef41e..a58281f 100644 --- a/lib/Models/tabletContext.dart +++ b/lib/Models/tabletContext.dart @@ -23,6 +23,24 @@ class TabletAppContext with ChangeNotifier{ ApplicationInstanceDTO? applicationInstanceDTO; StatisticsService? statisticsService; + /// L'assistant demande deux feux verts : l'instance et le canal tablette. + /// Avant Postgres v3, `applicationInstanceDTO != null` en tenait lieu — il n'était + /// assigné que si l'instance avait l'IA. Ce DTO portant désormais aussi les + /// réglages d'affichage, il est toujours assigné : le drapeau est explicite. + bool isAssistantEnabled = false; + + /// Retourne l'AppConfigurationLink de l'instance pour la configuration courante. + /// Contient roundedValue, isSectionImageBackground, isDate, isHour, + /// screenPercentageSectionsMainPage — ces réglages ont quitté ConfigurationDTO + /// avec Postgres v3, ils sont désormais portés par le lien instance ↔ configuration. + /// Même getter que VisitAppContext dans mymuseum-visitapp. + AppConfigurationLink? get currentAppConfigurationLink { + if (applicationInstanceDTO == null || configuration == null) return null; + return applicationInstanceDTO!.configurations + ?.where((c) => c.configurationId == configuration!.id) + .firstOrNull; + } + TabletAppContext({this.id, this.deviceId, this.host, this.configuration, this.language, this.instanceId, this.apiKey, this.clientAPI}); Map toMap() { diff --git a/lib/Screens/Agenda/agenda_view.dart b/lib/Screens/Agenda/agenda_view.dart index ced9e6f..f808f31 100644 --- a/lib/Screens/Agenda/agenda_view.dart +++ b/lib/Screens/Agenda/agenda_view.dart @@ -52,7 +52,7 @@ class _AgendaView extends State { if (dtos == null) return null; final events = dtos - .map((dto) => EventAgenda.fromDto(dto, tabletAppContext.language)) + .map((dto) => EventAgenda.fromDto(dto, tabletAppContext.language ?? 'FR')) .toList(); events.sort((a, b) { if (a.dateFrom == null) return 1; @@ -110,7 +110,7 @@ class _AgendaView extends State { child: Container( decoration: BoxDecoration( color: kBackgroundColor, - borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 30.0)), + borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 30.0)), ), child: Padding( padding: const EdgeInsets.all(8.0), diff --git a/lib/Screens/Agenda/event_list_item.dart b/lib/Screens/Agenda/event_list_item.dart index 45ea188..236edaa 100644 --- a/lib/Screens/Agenda/event_list_item.dart +++ b/lib/Screens/Agenda/event_list_item.dart @@ -32,7 +32,7 @@ class EventListItem extends StatelessWidget { return Container( margin: const EdgeInsets.all(10.0), decoration: BoxDecoration( - borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0), + borderRadius: BorderRadius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0), //color: Colors.red, boxShadow: const [ BoxShadow( @@ -53,7 +53,7 @@ class EventListItem extends StatelessWidget { child: Stack( children: [ eventAgenda.image != null ? ClipRRect( - borderRadius: BorderRadius.only(topLeft: Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0), topRight: Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)), + borderRadius: BorderRadius.only(topLeft: Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0), topRight: Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0)), child: Container( //color: Colors.green, //constraints: const BoxConstraints(maxHeight: 175), @@ -82,7 +82,7 @@ class EventListItem extends StatelessWidget { decoration: BoxDecoration( color: primaryColor, borderRadius: BorderRadius.only( - topLeft: Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0), + topLeft: Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0), ), ), child: Padding( @@ -127,7 +127,7 @@ class EventListItem extends StatelessWidget { width: size.width, decoration: BoxDecoration( color: Colors.white, - borderRadius: BorderRadius.only(bottomLeft: Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0), bottomRight: Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)), + borderRadius: BorderRadius.only(bottomLeft: Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0), bottomRight: Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0)), border: Border(top: BorderSide(width: 0.1, color: kMainGrey)) ), child: Padding( diff --git a/lib/Screens/Agenda/event_popup.dart b/lib/Screens/Agenda/event_popup.dart index ca2362e..9fae5b4 100644 --- a/lib/Screens/Agenda/event_popup.dart +++ b/lib/Screens/Agenda/event_popup.dart @@ -106,13 +106,13 @@ class _EventPopupState extends State { return AlertDialog( shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)) + borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0)) ), contentPadding: EdgeInsets.zero, // title: Text(eventAgenda.name!), content: Container( decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)), + borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0)), color: kBackgroundColor, ), height: size.height * 0.85, @@ -151,7 +151,7 @@ class _EventPopupState extends State { Row( children: [ widget.eventAgenda.image != null ? ClipRRect( - borderRadius: BorderRadius.only(topLeft: Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0), bottomLeft: Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)), + borderRadius: BorderRadius.only(topLeft: Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0), bottomLeft: Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0)), child: Container( child: Center( child: Container( @@ -229,7 +229,7 @@ class _EventPopupState extends State { width: size.width * 0.38, decoration: BoxDecoration( color: kBackgroundLight, - borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)) + borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0)) ), child: Padding( padding: const EdgeInsets.only(left: 20, right: 10, bottom: 10, top: 15), diff --git a/lib/Screens/Configuration/config_view.dart b/lib/Screens/Configuration/config_view.dart index 53f01a0..82f484e 100644 --- a/lib/Screens/Configuration/config_view.dart +++ b/lib/Screens/Configuration/config_view.dart @@ -381,5 +381,22 @@ Future?> getConfigurations(dynamic appContext) async { //print(element); }); - return configurations.where((config) => config.isTablet!).toList(); + // `ConfigurationDTO.isTablet` a disparu avec Postgres v3 : le canal n'est plus une + // propriété de la configuration, il est porté par l'ApplicationInstance, et le + // rattachement vit dans ses AppConfigurationLink. Même source que main_view. + if (tabletAppContext.instanceId == null) return configurations; + + final instanceDTO = await tabletAppContext.clientAPI!.instanceApi! + .instanceGetDetail(tabletAppContext.instanceId!); + + final tabletConfigurationIds = instanceDTO?.applicationInstanceDTOs + ?.where((a) => a.appType == AppType.Tablet) + .expand((a) => a.configurations ?? const []) + .map((link) => link.configurationId) + .toSet() ?? + const {}; + + return configurations + .where((config) => tabletConfigurationIds.contains(config.id)) + .toList(); } \ No newline at end of file diff --git a/lib/Screens/Puzzle/correct_overlay.dart b/lib/Screens/Game/correct_overlay.dart similarity index 100% rename from lib/Screens/Puzzle/correct_overlay.dart rename to lib/Screens/Game/correct_overlay.dart diff --git a/lib/Screens/Game/game_page.dart b/lib/Screens/Game/game_page.dart new file mode 100644 index 0000000..a2e8d79 --- /dev/null +++ b/lib/Screens/Game/game_page.dart @@ -0,0 +1,517 @@ +import 'dart:math'; +import 'dart:async'; + +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_widget_from_html/flutter_widget_from_html.dart'; +import 'package:manager_api_new/api.dart'; +import 'package:tablet_app/Components/loading_common.dart'; +import 'package:tablet_app/Helpers/translationHelper.dart'; +import 'package:tablet_app/Models/tabletContext.dart'; +import 'package:tablet_app/Screens/Game/message_dialog.dart'; +import 'package:tablet_app/app_context.dart'; +import 'package:tablet_app/constants.dart'; +import 'package:provider/provider.dart'; +import 'package:tablet_app/Screens/Game/sliding_puzzle_piece.dart'; +import 'puzzle_piece.dart'; + +const IMAGE_PATH = 'image_path'; + +class GamePage extends StatefulWidget { + final GameDTO section; + GamePage({required this.section}); + + @override + _GamePage createState() => _GamePage(); +} + +class _GamePage extends State { + GameDTO gameDTO = GameDTO(); + + int allInPlaceCount = 0; + bool isFinished = false; + DateTime? _gameStartTime; + GlobalKey _widgetKey = GlobalKey(); + Size? realWidgetSize; + List pieces = []; + + bool isSplittingImage = true; + bool showHint = false; + List slidingTileIndices = []; // Maps current slot index to original tile index. -1 for empty. + int emptySlotIndex = -1; + + @override + void initState() { + //puzzleDTO = PuzzleDTO.fromJson(jsonDecode(widget.section!.data!))!; + gameDTO = widget.section; + gameDTO.rows = gameDTO.rows ?? 3; + gameDTO.cols = gameDTO.cols ?? 3; + _gameStartTime = DateTime.now(); + + WidgetsBinding.instance.addPostFrameCallback((_) async { + Size size = MediaQuery.of(context).size; + final appContext = Provider.of(context, listen: false); + TabletAppContext tabletAppContext = appContext.getContext(); + + print(gameDTO.messageDebut); + TranslationAndResourceDTO? messageDebut = gameDTO.messageDebut != null && gameDTO.messageDebut!.isNotEmpty ? gameDTO.messageDebut!.where((message) => message.language!.toUpperCase() == tabletAppContext.language!.toUpperCase()).firstOrNull : null; + + //await Future.delayed(const Duration(milliseconds: 50)); + + await WidgetsBinding.instance.endOfFrame; + getRealWidgetSize(); + + if(gameDTO.puzzleImage != null && gameDTO.puzzleImage!.url != null) { + //splitImage(Image.network(puzzleDTO.image!.resourceUrl!)); + splitImage(CachedNetworkImage( + imageUrl: gameDTO.puzzleImage!.url!, + fit: BoxFit.fill, + errorWidget: (context, url, error) => Icon(Icons.error), + )); + } else { + setState(() { + isSplittingImage = false; + }); + } + + if(messageDebut != null) { + showMessage(messageDebut, appContext, context, size); + } + }); + + super.initState(); + } + + Future getRealWidgetSize() async { + RenderBox renderBox = _widgetKey.currentContext?.findRenderObject() as RenderBox; + Size size = renderBox.size; + + setState(() { + realWidgetSize = size; + }); + print("Taille réelle du widget : $size"); + } + + // here we will split the image into small pieces + // using the rows and columns defined above; each piece will be added to a stack + void splitImage(CachedNetworkImage image) async { + final Completer completer = Completer(); + final ImageProvider provider = CachedNetworkImageProvider(gameDTO.puzzleImage!.url!); + + provider.resolve(const ImageConfiguration()).addListener( + ImageStreamListener((ImageInfo info, bool _) { + if (!completer.isCompleted) { + completer.complete(Size(info.image.width.toDouble(), info.image.height.toDouble())); + } + }), + ); + + Size imageOriginalSize = await completer.future; + double imageAspectRatio = imageOriginalSize.width / imageOriginalSize.height; + + // Calculate best fit for the puzzle inside the available area + double containerWidth = realWidgetSize!.width * 0.9; // 90% of available width + double containerHeight = realWidgetSize!.height * 0.8; // 80% of available height + double containerAspectRatio = containerWidth / containerHeight; + + double puzzleWidth, puzzleHeight; + if (imageAspectRatio > containerAspectRatio) { + puzzleWidth = containerWidth; + puzzleHeight = containerWidth / imageAspectRatio; + } else { + puzzleHeight = containerHeight; + puzzleWidth = containerHeight * imageAspectRatio; + } + + final appContext = Provider.of(context, listen: false); + TabletAppContext tabletAppContext = appContext.getContext(); + setState(() { + tabletAppContext.puzzleSize = Size(puzzleWidth, puzzleHeight); + appContext.setContext(tabletAppContext); + }); + + final pieceWidth = puzzleWidth / gameDTO.cols!; + final pieceHeight = puzzleHeight / gameDTO.rows!; + + if (gameDTO.gameType == GameTypes.SlidingPuzzle) { + // Initialize sliding puzzle slots: 0 to N-2 are tiles, last one is empty (-1) + int totalTiles = gameDTO.rows! * gameDTO.cols!; + slidingTileIndices = List.generate(totalTiles, (i) => i); + + // Shuffle by making random valid moves to ensure solvability + emptySlotIndex = totalTiles - 1; + slidingTileIndices[emptySlotIndex] = -1; // -1 represents the empty slot + + // Perform enough random moves to shuffle decently + int shuffleMoves = 100; + Random random = Random(); + for (int i = 0; i < shuffleMoves; i++) { + List adjacent = _getAdjacentIndices(emptySlotIndex, gameDTO.rows!, gameDTO.cols!); + int moveIndex = adjacent[random.nextInt(adjacent.length)]; + // Swap empty slot with the adjacent tile + slidingTileIndices[emptySlotIndex] = slidingTileIndices[moveIndex]; + slidingTileIndices[moveIndex] = -1; + emptySlotIndex = moveIndex; + } + } else { + for (int x = 0; x < gameDTO.rows!; x++) { + for (int y = 0; y < gameDTO.cols!; y++) { + // Target position in the puzzle grid + double targetLeft = y * pieceWidth; + double targetTop = x * pieceHeight; + + // Scatter logic: Randomly place within the container. + double initialLeft = Random().nextDouble() * (containerWidth - pieceWidth); + double initialTop = Random().nextDouble() * (containerHeight - pieceHeight); + + setState(() { + pieces.add( + PuzzlePiece( + key: GlobalKey(), + image: image, + imageSize: Size(puzzleWidth, puzzleHeight), + row: x, + col: y, + maxRow: gameDTO.rows!, + maxCol: gameDTO.cols!, + bringToTop: bringToTop, + sendToBack: sendToBack, + initialLeft: initialLeft - targetLeft, + initialTop: initialTop - targetTop, + ), + ); + }); + } + } + } + + setState(() { + isSplittingImage = false; + }); + } + + List _getAdjacentIndices(int index, int rows, int cols) { + List adjacent = []; + int r = index ~/ cols; + int c = index % cols; + + if (r > 0) adjacent.add(index - cols); // Top + if (r < rows - 1) adjacent.add(index + cols); // Bottom + if (c > 0) adjacent.add(index - 1); // Left + if (c < cols - 1) adjacent.add(index + 1); // Right + + return adjacent; + } + + void _onSlidingTileTapped(int currentSlot) { + if (isFinished) return; + + // Check if empty slot is adjacent + List adjacent = _getAdjacentIndices(currentSlot, gameDTO.rows!, gameDTO.cols!); + if (adjacent.contains(emptySlotIndex)) { + setState(() { + // Swap + slidingTileIndices[emptySlotIndex] = slidingTileIndices[currentSlot]; + slidingTileIndices[currentSlot] = -1; + emptySlotIndex = currentSlot; + + // Check win condition + bool won = true; + for (int i = 0; i < slidingTileIndices.length; i++) { + // In a solved puzzle, index i should contain tile i (or -1 at the very last slot) + if (i == slidingTileIndices.length - 1) { + if (slidingTileIndices[i] != -1) won = false; + } else { + if (slidingTileIndices[i] != i) won = false; + } + } + + if (won) { + isFinished = true; + _onGameFinished('SlidingPuzzle'); + } + }); + } + } + + // when the pan of a piece starts, we need to bring it to the front of the stack + void bringToTop(Widget widget) { + setState(() { + pieces.remove(widget); + pieces.add(widget); + }); + } + + // when a piece reaches its final position, + // it will be sent to the back of the stack to not get in the way of other, still movable, pieces + void sendToBack(Widget widget) { + setState(() { + allInPlaceCount++; + isFinished = allInPlaceCount == gameDTO.rows! * gameDTO.cols!; + pieces.remove(widget); + pieces.insert(0, widget); + + if (isFinished) { + _onGameFinished('Puzzle'); + } + }); + } + + void _onGameFinished(String gameType) { + Size size = MediaQuery.of(context).size; + final appContext = Provider.of(context, listen: false); + TabletAppContext tabletAppContext = appContext.getContext(); + final duration = _gameStartTime != null ? DateTime.now().difference(_gameStartTime!).inSeconds : 0; + + tabletAppContext.statisticsService?.track( + VisitEventType.gameComplete, + metadata: {'gameType': gameType, 'durationSeconds': duration}, + ); + + TranslationAndResourceDTO? messageFin = gameDTO.messageFin != null && gameDTO.messageFin!.isNotEmpty ? gameDTO.messageFin!.where((message) => message.language!.toUpperCase() == tabletAppContext.language!.toUpperCase()).firstOrNull : null; + + if(messageFin != null) { + showMessage(messageFin, appContext, context, size); + } + } + + /// mymuseum code ces couleurs en dur par flavor client (rouge MDLF, bleu Fort). + /// tablet-app n'a pas de flavor : un seul APK sert tous les clients et la charte + /// vient de la configuration choisie au pincode. Le dégradé en est donc dérivé, + /// sinon l'écran s'afficherait en bleu chez un client dont la charte est rouge. + Color _primaryColor(TabletAppContext tabletAppContext) { + final raw = tabletAppContext.configuration?.primaryColor; + if (raw == null) return kTestSecondColor; + return Color(int.parse(raw.split('(0x')[1].split(')')[0], radix: 16)); + } + + List _gradientColors(TabletAppContext tabletAppContext) { + final base = _primaryColor(tabletAppContext); + return [ + base, + Color.lerp(base, Colors.white, 0.15)!, + Color.lerp(base, Colors.white, 0.30)!, + ]; + } + + Widget _buildContent(TabletAppContext tabletAppContext) { + if (gameDTO.gameType == GameTypes.SlidingPuzzle) { + if (slidingTileIndices.isEmpty) return Center(child: LoadingCommon()); + + final puzzleSize = tabletAppContext.puzzleSize ?? Size(realWidgetSize!.width * 0.8, realWidgetSize!.height * 0.6); + final tileWidth = puzzleSize.width / gameDTO.cols!; + final tileHeight = puzzleSize.height / gameDTO.rows!; + + return Center( + child: Container( + width: puzzleSize.width, + height: puzzleSize.height, + child: Stack( + children: [ + // Hint Background + if (showHint) + Opacity( + opacity: 0.25, + child: CachedNetworkImage( + imageUrl: gameDTO.puzzleImage!.url!, + fit: BoxFit.fill, + ), + ), + // Tiles + for (int i = 0; i < slidingTileIndices.length; i++) + if (slidingTileIndices[i] != -1) // Don't draw the empty slot + AnimatedPositioned( + key: ValueKey('tile_${slidingTileIndices[i]}'), + duration: const Duration(milliseconds: 250), + curve: Curves.easeInOut, + left: (i % gameDTO.cols!) * tileWidth, + top: (i ~/ gameDTO.cols!) * tileHeight, + child: SlidingPuzzlePiece( + image: CachedNetworkImage(imageUrl: gameDTO.puzzleImage!.url!, fit: BoxFit.fill), + imageSize: puzzleSize, + originalRow: slidingTileIndices[i] ~/ gameDTO.cols!, + originalCol: slidingTileIndices[i] % gameDTO.cols!, + maxRows: gameDTO.rows!, + maxCols: gameDTO.cols!, + width: tileWidth, + height: tileHeight, + showNumberHint: showHint, + onTap: () => _onSlidingTileTapped(i), + ), + ), + ], + ), + ), + ); + } + + // Default: Puzzle + if (gameDTO.puzzleImage == null || gameDTO.puzzleImage!.url == null || realWidgetSize == null) { + return Center(child: Text("Aucune image à afficher", style: TextStyle(fontSize: kNoneInfoOrIncorrect))); + } + + final puzzleSize = tabletAppContext.puzzleSize ?? Size(realWidgetSize!.width * 0.8, realWidgetSize!.height * 0.6); + + return Center( + child: Container( + width: puzzleSize.width, + height: puzzleSize.height, + child: Stack( + clipBehavior: Clip.none, + children: [ + // Hint Background + if (showHint) + Opacity( + opacity: 0.2, // Unified opacity for both + child: CachedNetworkImage( + imageUrl: gameDTO.puzzleImage!.url!, + fit: BoxFit.fill, + ), + ), + ...pieces, + ], + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + final appContext = Provider.of(context); + TabletAppContext tabletAppContext = appContext.getContext(); + Size size = MediaQuery.of(context).size; + var title = TranslationHelper.get(widget.section.title, appContext.getContext()); + String cleanedTitle = title.replaceAll('\n', ' ').replaceAll('
', ' '); + + return Stack( + children: [ + Container( + height: size.height * 0.28, + decoration: BoxDecoration( + boxShadow: const [ + BoxShadow( + color: kMainGrey, + spreadRadius: 0.5, + blurRadius: 5, + offset: Offset(0, 1), // changes position of shadow + ), + ], + gradient: LinearGradient( + begin: Alignment.centerRight, + end: Alignment.centerLeft, + colors: _gradientColors(tabletAppContext), + ), + image: widget.section.imageSource != null ? DecorationImage( + fit: BoxFit.cover, + opacity: 0.65, + image: NetworkImage( + widget.section.imageSource!, + ), + ): null, + ), + ), + Column( + children: [ + SizedBox( + height: size.height * 0.11, + width: size.width, + child: Stack( + fit: StackFit.expand, + children: [ + Center( + child: Padding( + padding: const EdgeInsets.only(top: 22.0), + child: SizedBox( + width: size.width *0.7, + child: HtmlWidget( + cleanedTitle, + textStyle: const TextStyle(color: Colors.white, fontFamily: 'Roboto', fontSize: 20), + customStylesBuilder: (element) + { + return {'text-align': 'center', 'font-family': "Roboto", '-webkit-line-clamp': "2"}; + }, + ), + ), + ), + ), + Positioned( + top: 35, + left: 10, + child: SizedBox( + width: 50, + height: 50, + child: InkWell( + onTap: () { + Navigator.of(context).pop(); + }, + child: Container( + decoration: BoxDecoration( + color: _primaryColor(tabletAppContext), + shape: BoxShape.circle, + ), + child: const Icon(Icons.arrow_back, size: 23, color: Colors.white) + ), + ) + ), + ), + ], + ), + ), + Expanded( + child: Container( + margin: const EdgeInsets.only(top: 0), + decoration: const BoxDecoration( + boxShadow: [ + BoxShadow( + color: kMainGrey, + spreadRadius: 0.5, + blurRadius: 2, + offset: Offset(0, 1), // changes position of shadow + ), + ], + color: kBackgroundColor, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(30), + topRight: Radius.circular(30), + ), + ), + child: ClipRRect( + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(30), + topRight: Radius.circular(30), + ), + child: Center( + //color: Colors.green, + child: Container( + //color: Colors.green, + child: Padding( + key: _widgetKey, + padding: const EdgeInsets.all(0.0), + child: isSplittingImage ? Center(child: LoadingCommon()) : _buildContent(tabletAppContext), + ), + ), + ) + ) + ), + ), + ], + ), + if (gameDTO.gameType == null || gameDTO.gameType == GameTypes.Puzzle || gameDTO.gameType == GameTypes.SlidingPuzzle) + Positioned( + bottom: 25, + right: 20, + child: FloatingActionButton( + heroTag: 'hint_button', + onPressed: () { + setState(() { + showHint = !showHint; + }); + }, + backgroundColor: showHint ? _primaryColor(tabletAppContext) : Colors.grey[400], + child: const Icon(Icons.help_outline, color: Colors.white, size: 28), + ), + ), + ], + ); + } +} \ No newline at end of file diff --git a/lib/Screens/Puzzle/message_dialog.dart b/lib/Screens/Game/message_dialog.dart similarity index 91% rename from lib/Screens/Puzzle/message_dialog.dart rename to lib/Screens/Game/message_dialog.dart index fe82b0d..714061d 100644 --- a/lib/Screens/Puzzle/message_dialog.dart +++ b/lib/Screens/Game/message_dialog.dart @@ -15,7 +15,7 @@ void showMessage(TranslationAndResourceDTO translationAndResourceDTO, AppContext showDialog( builder: (BuildContext context) => AlertDialog( shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)) + borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0)) ), content: SingleChildScrollView( child: Column( @@ -24,13 +24,14 @@ void showMessage(TranslationAndResourceDTO translationAndResourceDTO, AppContext children: [ if(translationAndResourceDTO.resourceId != null) Container( + constraints: BoxConstraints(maxHeight: 250), //color: Colors.cyan, height: size.height *0.45, width: size.width *0.5, child: Center( child: Container( decoration: BoxDecoration( - borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 30), + borderRadius: BorderRadius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 30), //border: Border.all(width: 3, color: Colors.black) ), child: showElementForResource(ResourceDTO(id: translationAndResourceDTO.resourceId, type: translationAndResourceDTO.resource!.type, url: translationAndResourceDTO.resource!.url), appContext, true, false), @@ -38,6 +39,7 @@ void showMessage(TranslationAndResourceDTO translationAndResourceDTO, AppContext ), ), Container( + constraints: BoxConstraints(maxHeight: 350), //color: Colors.green, height: size.height *0.3, width: size.width *0.5, @@ -51,7 +53,7 @@ void showMessage(TranslationAndResourceDTO translationAndResourceDTO, AppContext customStylesBuilder: (element) { return {'text-align': 'center', 'font-family': "Roboto"}; }, - textStyle: TextStyle(fontSize: kDescriptionSize), + textStyle: const TextStyle(fontSize: kDescriptionSize), ),/*Text( resourceDTO.label == null ? "" : resourceDTO.label, style: new TextStyle(fontSize: 25, fontWeight: FontWeight.w400)),*/ diff --git a/lib/Screens/Puzzle/puzzle_piece.dart b/lib/Screens/Game/puzzle_piece.dart similarity index 60% rename from lib/Screens/Puzzle/puzzle_piece.dart rename to lib/Screens/Game/puzzle_piece.dart index c464f4e..1f1eb78 100644 --- a/lib/Screens/Puzzle/puzzle_piece.dart +++ b/lib/Screens/Game/puzzle_piece.dart @@ -1,10 +1,5 @@ -import 'dart:math'; - import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; -import 'package:tablet_app/Models/tabletContext.dart'; -import 'package:tablet_app/app_context.dart'; class PuzzlePiece extends StatefulWidget { final CachedNetworkImage image; @@ -15,31 +10,22 @@ class PuzzlePiece extends StatefulWidget { final int maxCol; final Function bringToTop; final Function sendToBack; + final double initialTop; + final double initialLeft; - static PuzzlePiece fromMap(Map map) { - return PuzzlePiece( - image: map['image'], - imageSize: map['imageSize'], - row: map['row'], - col: map['col'], - maxRow: map['maxRow'], - maxCol: map['maxCol'], - bringToTop: map['bringToTop'], - sendToBack: map['SendToBack'], - ); - } - - PuzzlePiece( - {Key? key, - required this.image, - required this.imageSize, - required this.row, - required this.col, - required this.maxRow, - required this.maxCol, - required this.bringToTop, - required this.sendToBack}) - : super(key: key); + PuzzlePiece({ + Key? key, + required this.image, + required this.imageSize, + required this.row, + required this.col, + required this.maxRow, + required this.maxCol, + required this.bringToTop, + required this.sendToBack, + required this.initialTop, + required this.initialLeft, + }) : super(key: key); @override _PuzzlePieceState createState() => _PuzzlePieceState(); @@ -58,65 +44,32 @@ class _PuzzlePieceState extends State { @override void initState() { super.initState(); + top = widget.initialTop; + left = widget.initialLeft; - WidgetsBinding.instance.addPostFrameCallback((_) { - setState(() { - - RenderBox renderBox = _widgetPieceKey.currentContext?.findRenderObject() as RenderBox; - Size size = renderBox.size; - - final appContext = Provider.of(context, listen: false); - TabletAppContext tabletAppContext = appContext.getContext(); - tabletAppContext.puzzleSize = size; - appContext.setContext(tabletAppContext); - - if(widget.row == 0 && widget.col == 0) { - widget.sendToBack(widget); - } - }); - }); + if (widget.row == 0 && widget.col == 0) { + isMovable = false; + top = 0; + left = 0; + } } @override Widget build(BuildContext context) { - - var isPortrait = MediaQuery.of(context).orientation == Orientation.portrait; - - var imageHeight = isPortrait ? widget.imageSize.width/1.55 : widget.imageSize.width; - var imageWidth = isPortrait ? widget.imageSize.width/1.55 : widget.imageSize.height; - - final pieceWidth = imageWidth / widget.maxCol; - final pieceHeight = imageHeight / widget.maxRow; - - if (top == null) { - top = Random().nextInt((imageHeight - pieceHeight).ceil()).toDouble(); - var test = top!; - test -= widget.row * pieceHeight; - top = test /7; // TODO change ? - } - - if (left == null) { - left = Random().nextInt((imageWidth - pieceWidth).ceil()).toDouble(); - var test = left!; - test -= widget.col * pieceWidth; - left = test /7; // TODO change ? - } - - if(widget.row == 0 && widget.col == 0) { - top = 0; - left = 0; - isMovable = false; - } - - return Positioned( - top: top, - left: left, - width: imageWidth, + return AnimatedPositioned( + duration: isMovable ? Duration.zero : const Duration(milliseconds: 300), + curve: Curves.easeOutBack, + top: top, + left: left, + width: widget.imageSize.width, + child: AnimatedScale( + duration: const Duration(milliseconds: 300), + scale: isMovable ? 1.05 : 1.0, child: Container( key: _widgetPieceKey, decoration: widget.col == 0 && widget.row == 0 ? BoxDecoration( border: Border.all( - color: Colors.black, + color: Colors.black.withOpacity(0.3), width: 0.5, ), ) : null, @@ -134,34 +87,40 @@ class _PuzzlePieceState extends State { onPanUpdate: (dragUpdateDetails) { if (isMovable) { setState(() { - var testTop = top!; - var testLeft = left!; - testTop = top!; - testLeft = left!; - testTop += dragUpdateDetails.delta.dy; - testLeft += dragUpdateDetails.delta.dx; - top = testTop; - left = testLeft; + top = top! + dragUpdateDetails.delta.dy; + left = left! + dragUpdateDetails.delta.dx; - if (-10 < top! && top! < 10 && -10 < left! && left! < 10) { - top = 0; - left = 0; - isMovable = false; + // Target position is (0,0) relative to its original offset in the image + if (top!.abs() < 15 && left!.abs() < 15) { + setState(() { + top = 0; + left = 0; + isMovable = false; + }); widget.sendToBack(widget); } }); } }, - child: ClipPath( - child: CustomPaint( - foregroundPainter: PuzzlePiecePainter( - widget.row, widget.col, widget.maxRow, widget.maxCol), - child: widget.image), + child: PhysicalShape( clipper: PuzzlePieceClipper( widget.row, widget.col, widget.maxRow, widget.maxCol), + elevation: isMovable ? 4.0 : 0.0, + color: Colors.transparent, + shadowColor: Colors.black.withOpacity(0.5), + child: ClipPath( + child: CustomPaint( + foregroundPainter: PuzzlePiecePainter( + widget.row, widget.col, widget.maxRow, widget.maxCol), + child: widget.image), + clipper: PuzzlePieceClipper( + widget.row, widget.col, widget.maxRow, widget.maxCol), + ), ), ), - )); + ), + ), + ); } } @@ -195,9 +154,9 @@ class PuzzlePiecePainter extends CustomPainter { @override void paint(Canvas canvas, Size size) { final Paint paint = Paint() - ..color = Colors.black//Color(0x80FFFFFF) + ..color = Colors.black.withOpacity(0.2) ..style = PaintingStyle.stroke - ..strokeWidth = 2.5; + ..strokeWidth = 1.0; canvas.drawPath(getPiecePath(size, row, col, maxRow, maxCol), paint); } diff --git a/lib/Screens/Puzzle/score_widget.dart b/lib/Screens/Game/score_widget.dart similarity index 100% rename from lib/Screens/Puzzle/score_widget.dart rename to lib/Screens/Game/score_widget.dart diff --git a/lib/Screens/Game/sliding_puzzle_piece.dart b/lib/Screens/Game/sliding_puzzle_piece.dart new file mode 100644 index 0000000..460540f --- /dev/null +++ b/lib/Screens/Game/sliding_puzzle_piece.dart @@ -0,0 +1,88 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; + +class SlidingPuzzlePiece extends StatelessWidget { + final CachedNetworkImage image; + final Size imageSize; + final int originalRow; + final int originalCol; + final int maxRows; + final int maxCols; + final VoidCallback onTap; + final double width; + final double height; + final bool showNumberHint; + + const SlidingPuzzlePiece({ + Key? key, + required this.image, + required this.imageSize, + required this.originalRow, + required this.originalCol, + required this.maxRows, + required this.maxCols, + required this.onTap, + required this.width, + required this.height, + this.showNumberHint = false, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: onTap, + child: Container( + width: width, + height: height, + margin: const EdgeInsets.all(2), // Subtle gap + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.2), + blurRadius: 4, + offset: const Offset(0, 2), + ), + ], + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Stack( + children: [ + OverflowBox( + maxWidth: imageSize.width, + maxHeight: imageSize.height, + alignment: Alignment( + maxCols == 1 ? 0.0 : -1.0 + (originalCol * 2 / (maxCols - 1)), + maxRows == 1 ? 0.0 : -1.0 + (originalRow * 2 / (maxRows - 1)), + ), + child: image, + ), + if (showNumberHint) + Container( + color: Colors.black.withOpacity(0.3), + child: Center( + child: Text( + '${originalRow * maxCols + originalCol + 1}', + style: const TextStyle( + color: Colors.white, + fontSize: 24, + fontWeight: FontWeight.bold, + shadows: [ + Shadow( + blurRadius: 4.0, + color: Colors.black, + offset: Offset(0, 0), + ), + ], + ), + ), + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/Screens/MainView/main_view.dart b/lib/Screens/MainView/main_view.dart index f8625c4..c4f4060 100644 --- a/lib/Screens/MainView/main_view.dart +++ b/lib/Screens/MainView/main_view.dart @@ -31,7 +31,7 @@ import 'package:tablet_app/Screens/Map/map_view.dart'; import 'package:tablet_app/Models/tabletContext.dart'; import 'package:tablet_app/Screens/Menu/menu_view.dart'; import 'package:tablet_app/Screens/PDF/pdf_view.dart'; -import 'package:tablet_app/Screens/Puzzle/puzzle_view.dart'; +import 'package:tablet_app/Screens/Game/game_page.dart'; import 'package:tablet_app/Screens/Slider/slider_view.dart'; import 'package:tablet_app/Screens/Video/video_view.dart'; import 'package:tablet_app/Screens/Web/web_view.dart'; @@ -58,6 +58,11 @@ class _MainViewWidget extends State { Size sizeScreen = new Size(1080.0, 1920.0); // Tablet resolution SectionDTO? sectionSelected; late ConfigurationDTO configurationDTO; + + /// isDate, isHour, isSectionImageBackground et screenPercentageSectionsMainPage + /// ont quitté ConfigurationDTO avec Postgres v3 : ils vivent sur le lien + /// instance ↔ configuration. + AppConfigurationLink? appConfigurationLink; ValueNotifier currentHourDate = ValueNotifier((DateTime.now().toUtc()).add(Duration(hours: 1))); late Color backgroundColor; int rowCount = 4; @@ -77,11 +82,12 @@ class _MainViewWidget extends State { configurationDTO = appContext.getContext().configuration; - if(configurationDTO.isHour != null && configurationDTO.isHour!) { + appConfigurationLink = appContext.getContext().currentAppConfigurationLink; + if(appConfigurationLink?.isHour == true) { Timer.periodic(Duration(seconds: 1), (Timer t) => _getTime(currentHourDate)); } - isImageBackground = configurationDTO.isSectionImageBackground ?? true; + isImageBackground = appConfigurationLink?.isSectionImageBackground ?? true; super.initState(); } @@ -138,12 +144,12 @@ class _MainViewWidget extends State { mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.start, children: [ - if(value != null && configurationDTO.isHour!) + if(value != null && appConfigurationLink?.isHour == true) Text(DateFormat('HH:mm').format(value), style: TextStyle(fontSize: 20, color: textColor)), - if(value != null && configurationDTO.isDate!) + if(value != null && appConfigurationLink?.isDate == true) if(appContext.getContext().language.toString().toUpperCase() == "EN") Text(DateFormat('MM/dd').format(value), style: TextStyle(fontSize: 15, color: textColor)), - if(value != null && configurationDTO.isDate!) + if(value != null && appConfigurationLink?.isDate == true) if(appContext.getContext().language.toString().toUpperCase() != "EN") Text(DateFormat('dd/MM').format(value), style: TextStyle(fontSize: 15, color: textColor)), ], @@ -155,7 +161,7 @@ class _MainViewWidget extends State { LanguageSelection(size: size), Center( child: Container( - height: configurationDTO.screenPercentageSectionsMainPage != null ? size.height * (configurationDTO.screenPercentageSectionsMainPage! / 100) : size.height * 0.85, + height: appConfigurationLink?.screenPercentageSectionsMainPage != null ? size.height * (appConfigurationLink!.screenPercentageSectionsMainPage! / 100) : size.height * 0.85, width: size.width * 0.9, child: isInit ? FutureBuilder( future: getSections(size, appContext), @@ -197,7 +203,7 @@ class _MainViewWidget extends State { ), ) ), - if (tabletAppContext.applicationInstanceDTO?.isAssistant == true) + if (tabletAppContext.isAssistantEnabled) Positioned( bottom: 24, right: 24, @@ -304,7 +310,7 @@ class _MainViewWidget extends State { var result = await showDialog( builder: (BuildContext dialogContext) => AlertDialog( shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)) + borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0)) ), content: Container( width: 400, @@ -330,9 +336,15 @@ class _MainViewWidget extends State { .where((a) => a.appType == AppType.Tablet) .firstOrNull; if (tabletInstance != null) { - if (instanceDTO.isAssistant == true) { - tabletAppContext.applicationInstanceDTO = tabletInstance; - } + // Assigné inconditionnellement : ce DTO ne sert plus seulement de drapeau + // d'assistant, il porte aussi les AppConfigurationLink d'où viennent + // roundedValue, isDate, isHour, isSectionImageBackground et + // screenPercentageSectionsMainPage depuis Postgres v3. Le laisser null + // sur une instance sans IA renverrait tous ces réglages à leurs valeurs + // par défaut, sans erreur visible. + tabletAppContext.applicationInstanceDTO = tabletInstance; + tabletAppContext.isAssistantEnabled = + instanceDTO.isAssistant == true && tabletInstance.isAssistant == true; if (tabletInstance.hasStats == true) { tabletAppContext.statisticsService = StatisticsService( clientAPI: tabletAppContext.clientAPI!, @@ -485,7 +497,7 @@ boxDecoration(AppContext appContext, SectionDTO section, bool isSelected, Object return BoxDecoration( color: !isSelected ? kBackgroundLight : section.imageSource == null ? kBackgroundLight : null, shape: BoxShape.rectangle, - borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 30.0), + borderRadius: BorderRadius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 30.0), image: section.imageSource != null || section.type == SectionType.Video ? new DecorationImage( fit: BoxFit.cover, colorFilter: !isSelected? new ColorFilter.mode(kBackgroundLight.withValues(alpha: 0.2), BlendMode.dstATop) : null, @@ -632,9 +644,9 @@ Widget getContent(TabletAppContext tabletAppContext, SectionDTO sectionSelected, case SectionType.Pdf : PdfDTO pdfDTO = PdfDTO.fromJson(rawSectionData)!; return PDFViewWidget(section: pdfDTO); - case SectionType.Puzzle : - PuzzleDTO puzzleDTO = PuzzleDTO.fromJson(rawSectionData)!; - return PuzzleView(section: puzzleDTO); + case SectionType.Game : + GameDTO gameDTO = GameDTO.fromJson(rawSectionData)!; + return GamePage(section: gameDTO); case SectionType.Agenda : AgendaDTO agendaDTO = AgendaDTO.fromJson(rawSectionData)!; return AgendaView(section: agendaDTO); diff --git a/lib/Screens/MainView/section_page_detail.dart b/lib/Screens/MainView/section_page_detail.dart index 8d0b099..5f7244e 100644 --- a/lib/Screens/MainView/section_page_detail.dart +++ b/lib/Screens/MainView/section_page_detail.dart @@ -103,7 +103,7 @@ class _SectionPageDetailState extends State { decoration : BoxDecoration( color: kBackgroundLight, shape: BoxShape.rectangle, - borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 30.0), + borderRadius: BorderRadius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 30.0), boxShadow: [ BoxShadow( color: kBackgroundSecondGrey, @@ -179,7 +179,7 @@ class _SectionPageDetailState extends State { backgroundColor: kBackgroundColor, focusColor: kBackgroundColor, splashColor: kBackgroundColor, - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 30.0)), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 30.0)), onPressed: () { Navigator.pop(context); /*Navigator.of(context).pushReplacement( @@ -215,7 +215,7 @@ class _SectionPageDetailState extends State { /*decoration: sectionSelected!.type != SectionType.Video && sectionSelected!.type != SectionType.Web && sectionSelected!.type != SectionType.Slider && sectionSelected!.type != SectionType.Map ? BoxDecoration( //color: kBackgroundLight, shape: BoxShape.rectangle, - borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 30.0), + borderRadius: BorderRadius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 30.0), /*boxShadow: [ BoxShadow( color: kBackgroundSecondGrey, @@ -268,7 +268,7 @@ boxDecoration(AppContext appContext, SectionDTO section, bool isSelected) { return BoxDecoration( color: !isSelected ? kBackgroundLight : section.imageSource == null ? kBackgroundLight : null, shape: BoxShape.rectangle, - borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 30.0), + borderRadius: BorderRadius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 30.0), image: section.imageSource != null ? new DecorationImage( fit: BoxFit.cover, colorFilter: !isSelected? new ColorFilter.mode(kBackgroundLight.withValues(alpha: 0.2), BlendMode.dstATop) : null, diff --git a/lib/Screens/Map/flutter_map_view.dart b/lib/Screens/Map/flutter_map_view.dart index 3690611..7ea42c2 100644 --- a/lib/Screens/Map/flutter_map_view.dart +++ b/lib/Screens/Map/flutter_map_view.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:latlong2/latlong.dart'; import 'package:manager_api_new/api.dart'; +import 'package:tablet_app/Helpers/geo.dart'; import 'package:provider/provider.dart'; import 'package:tablet_app/Models/tabletContext.dart'; import 'package:tablet_app/Screens/Map/map_context.dart'; @@ -50,7 +51,7 @@ class _FlutterMapViewState extends State { Marker( width: 80.0, height: 80.0, - point: LatLng(double.tryParse(point.latitude!)!, double.tryParse(point.longitude!)!), + point: LatLng(point.lat!, point.lng!), child: GestureDetector( onTap: () { /*final mapContext = Provider.of(context, listen: false); @@ -85,7 +86,7 @@ class _FlutterMapViewState extends State { if (mapController == null) { // mapContext.getSelectedPointForNavigate() != null /*var geoPoint = mapContext.getSelectedPointForNavigate(); - var center = LatLng(double.tryParse(geoPoint.latitude!)!, double.tryParse(geoPoint.longitude!)!);*/ + var center = LatLng(geoPoint.lat!, geoPoint.lng!);*/ mapController = MapController(); //mapController!.move(center, widget.mapDTO!.zoom != null ? widget.mapDTO!.zoom!.toDouble() : 12); @@ -122,7 +123,7 @@ class _FlutterMapViewState extends State { var geoPoint = mapContext.getSelectedPointForNavigate() as GeoPointDTO?; if (geoPoint != null && mapController != null) { print("COUCOU IL FAUT NAVIGATE FLUTTER MAP"); - mapController!.move(LatLng(double.tryParse(geoPoint.latitude!)!, double.tryParse(geoPoint.longitude!)!), mapController!.camera.zoom/*, widget.mapDTO!.zoom != null ? widget.mapDTO!.zoom!.toDouble() : 16*/); // keep actual zoom + mapController!.move(LatLng(geoPoint.lat!, geoPoint.lng!), mapController!.camera.zoom/*, widget.mapDTO!.zoom != null ? widget.mapDTO!.zoom!.toDouble() : 16*/); // keep actual zoom } return SizedBox(); }, diff --git a/lib/Screens/Map/geo_point_filter.dart b/lib/Screens/Map/geo_point_filter.dart index 0f3d0a8..a9c5c7e 100644 --- a/lib/Screens/Map/geo_point_filter.dart +++ b/lib/Screens/Map/geo_point_filter.dart @@ -1,6 +1,5 @@ import 'dart:ui'; -import 'dart:math'; //import 'package:animated_tree_view/animated_tree_view.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -8,6 +7,7 @@ import 'package:flutter/material.dart'; //import 'package:generate_tree/generate_tree.dart'; //import 'package:generate_tree/treeNode.dart'; import 'package:manager_api_new/api.dart'; +import 'package:tablet_app/Helpers/geo.dart'; import 'package:provider/provider.dart'; import 'package:tablet_app/Helpers/translationHelper.dart'; import 'package:tablet_app/Models/tabletContext.dart'; @@ -77,9 +77,7 @@ class _GeoPointFilterState extends State { { if(pointWithoutCat.title!.where((l) => l.language == widget.language).firstOrNull != null) { TreeNode nodeWithoutCat = TreeNode( - id: 000 + int.parse( - (pointWithoutCat.latitude ?? '').substring(0, min(pointWithoutCat.latitude!.length, 10)).replaceAll(".", "").replaceAll("-","") + (pointWithoutCat.longitude ?? '').substring(0, min(pointWithoutCat.longitude!.length, 10)).replaceAll(".", "").replaceAll("-","") - ), + id: 000 + pointWithoutCat.coordinateKey, title: parse(pointWithoutCat.title!.firstWhere((l) => l.language == widget.language).value!).documentElement!.text, children: [], checked: true, // default true @@ -109,9 +107,7 @@ class _GeoPointFilterState extends State { for (var geoPoint in geoPoints.where((gp) => gp.categorieId != null)) { if (geoPoint.categorieId == category.id && geoPoint.title!.where((l) => l.language == widget.language).firstOrNull != null) { TreeNode geoPointNode = TreeNode( - id: 000 + int.parse( - (geoPoint.latitude ?? '').substring(0, min(geoPoint.latitude!.length, 10)).replaceAll(".", "").replaceAll("-", "") + (geoPoint.longitude ?? '').substring(0, min(geoPoint.longitude!.length, 10)).replaceAll(".", "").replaceAll("-", "") - ), + id: 000 + geoPoint.coordinateKey, title: parse(geoPoint.title!.firstWhere((l) => l.language == widget.language).value!).documentElement!.text, checked: true, // default true show: false, @@ -156,15 +152,7 @@ class _GeoPointFilterState extends State { if (childNode.checked) { var point = widget.geoPoints.firstWhere( (point) { - String latitudePart = (point.latitude ?? '') - .substring(0, min(point.latitude!.length, 10)) - .replaceAll(".", "") - .replaceAll("-", ""); - String longitudePart = (point.longitude ?? '') - .substring(0, min(point.longitude!.length, 10)) - .replaceAll(".", "") - .replaceAll("-", ""); - int combinedValue = int.parse(latitudePart + longitudePart); + int combinedValue = point.coordinateKey; return combinedValue == childNode.id; }, @@ -180,15 +168,7 @@ class _GeoPointFilterState extends State { if(node.checked) { var point = widget.geoPoints.firstWhere( (point) { - String latitudePart = (point.latitude ?? '') - .substring(0, min(point.latitude!.length, 10)) - .replaceAll(".", "") - .replaceAll("-", ""); - String longitudePart = (point.longitude ?? '') - .substring(0, min(point.longitude!.length, 10)) - .replaceAll(".", "") - .replaceAll("-", ""); - int combinedValue = int.parse(latitudePart + longitudePart); + int combinedValue = point.coordinateKey; return combinedValue == node.id; }, orElse: () => GeoPointDTO(id: -1), @@ -256,7 +236,7 @@ class _GeoPointFilterState extends State { width: size.width * 0.3, decoration: BoxDecoration( color: kBackgroundColor.withValues(alpha: 0.78), - borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)), + borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0)), ), child: Padding( padding: const EdgeInsets.all(8.0), @@ -285,7 +265,7 @@ class _GeoPointFilterState extends State { ), focusColor: primaryColor, focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)), + borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0)), borderSide: BorderSide(color: primaryColor)), //labelStyle: TextStyle(color: primaryColor), suffixIcon: IconButton( @@ -340,16 +320,7 @@ class _GeoPointFilterState extends State { onClicked: (node, commonID) { var selectedNode = widget.geoPoints.firstWhere( (point) { - String latitudePart = (point.latitude ?? '') - .substring(0, min(point.latitude!.length, 10)) - .replaceAll(".", "") - .replaceAll("-", ""); - String longitudePart = (point.longitude ?? '') - .substring(0, min(point.longitude!.length, 10)) - .replaceAll(".", "") - .replaceAll("-", ""); - - int combinedValue = int.parse(latitudePart + longitudePart); + int combinedValue = point.coordinateKey; return combinedValue == commonID; }, diff --git a/lib/Screens/Map/google_map_view.dart b/lib/Screens/Map/google_map_view.dart index db3c0b4..5a5a55d 100644 --- a/lib/Screens/Map/google_map_view.dart +++ b/lib/Screens/Map/google_map_view.dart @@ -3,6 +3,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:manager_api_new/api.dart'; +import 'package:tablet_app/Helpers/geo.dart'; import 'package:provider/provider.dart'; import 'package:tablet_app/Models/tabletContext.dart'; import 'package:tablet_app/Screens/Map/map_context.dart'; @@ -50,14 +51,14 @@ class _GoogleMapViewState extends State { latitude: point.latitude, contents: point.contents );*/ - if (point.latitude != null && point.longitude != null) { + if (point.lat != null && point.lng != null) { var icon = point.categorieId == null ? BitmapDescriptor.bytes(widget.icons.where((i) => i['id'] == null).first['icon']) : widget.icons.any((i) => i['id'] == point.categorieId) ? BitmapDescriptor.bytes(widget.icons.where((i) => i['id'] == point.categorieId).first['icon']) : BitmapDescriptor.bytes(widget.icons.where((i) => i['id'] == null).first['icon']); //widget.selectedMarkerIcon,; markers.add(Marker( draggable: false, - markerId: MarkerId(parse(textSansHTML.body!.text).documentElement!.text + point.latitude! + point.longitude!), + markerId: MarkerId(parse(textSansHTML.body!.text).documentElement!.text + point.lat!.toString() + point.lng!.toString()), position: LatLng( - double.tryParse(point.latitude!)!, - double.tryParse(point.longitude!)!, + point.lat!, + point.lng!, ), icon: icon, //widget.selectedMarkerIcon, //widget.selectedMarkerIcon != null ? BitmapDescriptor.fromBytes(widget.selectedMarkerIcon!) : BitmapDescriptor.defaultMarker, @@ -182,7 +183,7 @@ class _GoogleMapViewState extends State { _GoogleMapcontroller!.getZoomLevel().then((actualZoom) { _GoogleMapcontroller!.animateCamera(CameraUpdate.newCameraPosition( CameraPosition( - target: LatLng(double.tryParse(geopoint.latitude!)!, double.tryParse(geopoint.longitude!)!), + target: LatLng(geopoint.lat!, geopoint.lng!), tilt: 0.0, bearing: 0.0, zoom: actualZoom diff --git a/lib/Screens/Map/map_box_view.dart b/lib/Screens/Map/map_box_view.dart index de333ae..1153aca 100644 --- a/lib/Screens/Map/map_box_view.dart +++ b/lib/Screens/Map/map_box_view.dart @@ -3,6 +3,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:manager_api_new/api.dart'; +import 'package:tablet_app/Helpers/geo.dart'; import 'package:mapbox_maps_flutter/mapbox_maps_flutter.dart' as mapBox; import 'package:provider/provider.dart'; import 'package:tablet_app/Models/tabletContext.dart'; @@ -40,7 +41,7 @@ class AnnotationClickListener extends mapBox.OnPointAnnotationClickListener { @override void onPointAnnotationClick(mapBox.PointAnnotation annotation) { try{ - var markerToShow = markersList.firstWhere((ml) => "${parse(ml.title!.first.value).documentElement!.text}${ml.latitude}${ml.longitude}" == annotation.textField); + var markerToShow = markersList.firstWhere((ml) => "${parse(ml.title!.first.value).documentElement!.text}${ml.lat}${ml.lng}" == annotation.textField); mapContext.setSelectedPoint(markerToShow); //mapContext.setSelectedPointForNavigate(markerToShow); } catch(e) { @@ -76,11 +77,11 @@ class _MapBoxViewState extends State { options.add(mapBox.PointAnnotationOptions( geometry: mapBox.Point( coordinates: mapBox.Position( - double.tryParse(point.longitude!)!, - double.tryParse(point.latitude!)!, + point.lng!, + point.lat!, )), // .toJson() iconSize: 1.3, - textField: "${parse(textSansHTML.body!.text).documentElement!.text}${point.latitude}${point.longitude}", + textField: "${parse(textSansHTML.body!.text).documentElement!.text}${point.lat}${point.lng}", textOpacity: 0.0, iconOffset: [0.0, 0.0], symbolSortKey: 10, @@ -201,7 +202,7 @@ class _MapBoxViewState extends State { // TODO Handle zoomDetail mapboxMap?.easeTo( mapBox.CameraOptions( - center: mapBox.Point(coordinates: mapBox.Position(double.tryParse(geoPoint.longitude!)!, double.tryParse(geoPoint.latitude!)!)), //.toJson() + center: mapBox.Point(coordinates: mapBox.Position(geoPoint.lng!, geoPoint.lat!)), //.toJson() zoom: 16, bearing: 0, pitch: 3), diff --git a/lib/Screens/Map/marker_view.dart b/lib/Screens/Map/marker_view.dart index ff880eb..275c27b 100644 --- a/lib/Screens/Map/marker_view.dart +++ b/lib/Screens/Map/marker_view.dart @@ -73,7 +73,7 @@ class _MarkerInfoWidget extends State { decoration: BoxDecoration( color: kBackgroundColor, // Colors.amberAccent //kBackgroundLight, //shape: BoxShape.rectangle, - borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 10.0), + borderRadius: BorderRadius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 10.0), /*boxShadow: [ BoxShadow( color: kBackgroundSecondGrey, @@ -122,7 +122,7 @@ class _MarkerInfoWidget extends State { Row( children: [ selectedPoint.imageResourceId != null && selectedPoint.imageUrl != null ? ClipRRect( - borderRadius: BorderRadius.only(topLeft: Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0), bottomLeft: Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)), + borderRadius: BorderRadius.only(topLeft: Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0), bottomLeft: Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0)), child: Container( child: Center( child: Container( @@ -178,7 +178,7 @@ class _MarkerInfoWidget extends State { width: size.width * 0.38, decoration: BoxDecoration( color: kBackgroundLight, - borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)) + borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0)) ), child: Padding( padding: const EdgeInsets.only(left: 20, right: 10, bottom: 10, top: 15), @@ -215,7 +215,7 @@ class _MarkerInfoWidget extends State { width: size.width * 0.38, decoration: BoxDecoration( color: kBackgroundLight, - borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)) + borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0)) ), child: Padding( padding: const EdgeInsets.only(left: 20, right: 10, bottom: 10, top: 15), @@ -298,7 +298,7 @@ class _MarkerInfoWidget extends State { width: size.width * 0.38, decoration: BoxDecoration( color: kBackgroundLight, - borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)) + borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0)) ), child: Padding( padding: EdgeInsets.all(5), @@ -500,7 +500,7 @@ class _MarkerInfoWidget extends State { decoration: BoxDecoration( color: kBackgroundColor, shape: BoxShape.rectangle, - borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 10.0), + borderRadius: BorderRadius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 10.0), boxShadow: [ BoxShadow( color: kBackgroundSecondGrey, @@ -584,13 +584,13 @@ getElementForResource(BuildContext context, AppContext appContext, ContentDTO i, builder: (BuildContext context) { return AlertDialog( shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)) + borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0)) ), contentPadding: EdgeInsets.zero, // title: Text(eventAgenda.name!), content: Container( decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)), + borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0)), color: kBackgroundColor, ), height: size.height * 0.8, @@ -598,7 +598,7 @@ getElementForResource(BuildContext context, AppContext appContext, ContentDTO i, child: Container( decoration: BoxDecoration( //color: Colors.yellow, - borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 15.0)), + borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 15.0)), ), child: PhotoView( imageProvider: ImageCustomProvider.getImageProvider(appContext, i.resourceId!, i.resource!.url!), @@ -607,7 +607,7 @@ getElementForResource(BuildContext context, AppContext appContext, ContentDTO i, backgroundDecoration: BoxDecoration( color: kBackgroundGrey, shape: BoxShape.rectangle, - borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 15.0), + borderRadius: BorderRadius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 15.0), ), ), ), @@ -624,7 +624,7 @@ getElementForResource(BuildContext context, AppContext appContext, ContentDTO i, image: ImageCustomProvider.getImageProvider(appContext, i.resourceId!, i.resource!.url!), fit: BoxFit.cover, ), - borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 15.0)), + borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 15.0)), /*border: Border.all( color: kBackgroundGrey, width: 1.0, @@ -645,13 +645,13 @@ getElementForResource(BuildContext context, AppContext appContext, ContentDTO i, builder: (BuildContext context) { return AlertDialog( shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)) + borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0)) ), contentPadding: EdgeInsets.zero, // title: Text(eventAgenda.name!), content: Container( decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)), + borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0)), color: kBackgroundColor, ), height: size.height * 0.8, @@ -669,7 +669,7 @@ getElementForResource(BuildContext context, AppContext appContext, ContentDTO i, decoration: BoxDecoration( color: Colors.yellow, shape: BoxShape.rectangle, - borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 15.0), + borderRadius: BorderRadius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 15.0), ), child: showElementForResource(ResourceDTO(id: i.resourceId, url: i.resource?.url, type: i.resource?.type), appContext, false, true), ), diff --git a/lib/Screens/Menu/menu_view.dart b/lib/Screens/Menu/menu_view.dart index 46bbc58..8f027d9 100644 --- a/lib/Screens/Menu/menu_view.dart +++ b/lib/Screens/Menu/menu_view.dart @@ -169,7 +169,7 @@ boxDecoration(AppContext appContext, SectionDTO section, bool isSelected, Object return BoxDecoration( color: kBackgroundLight, shape: BoxShape.rectangle, - borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0), + borderRadius: BorderRadius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0), image: section.imageSource != null || section.type == SectionType.Video ? new DecorationImage( fit: BoxFit.cover, colorFilter: !isSelected? new ColorFilter.mode(kBackgroundLight.withValues(alpha: 0.35), BlendMode.dstATop) : null, diff --git a/lib/Screens/PDF/pdf_view.dart b/lib/Screens/PDF/pdf_view.dart index fe66224..b26dfd6 100644 --- a/lib/Screens/PDF/pdf_view.dart +++ b/lib/Screens/PDF/pdf_view.dart @@ -117,7 +117,7 @@ class _PDFViewWidget extends State { child: Container( decoration: BoxDecoration( color: kBackgroundColor, - borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)), + borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0)), ), child: Padding( padding: const EdgeInsets.all(8.0), @@ -185,7 +185,7 @@ class _PDFViewWidget extends State { builder: (context, value, _) { return Container( decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)), + borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0)), color: primaryColor ), child: Padding( diff --git a/lib/Screens/Puzzle/puzzle_view.dart b/lib/Screens/Puzzle/puzzle_view.dart deleted file mode 100644 index e711d8a..0000000 --- a/lib/Screens/Puzzle/puzzle_view.dart +++ /dev/null @@ -1,238 +0,0 @@ -import 'dart:convert'; -import 'dart:async'; -import 'dart:io'; - -import 'package:cached_network_image/cached_network_image.dart'; -import 'package:flutter/material.dart'; -import 'package:manager_api_new/api.dart'; -import 'package:provider/provider.dart'; -import 'package:tablet_app/Components/loading_common.dart'; -import 'package:tablet_app/Models/tabletContext.dart'; -import 'package:tablet_app/Screens/Puzzle/message_dialog.dart'; -import 'package:tablet_app/app_context.dart'; -import 'package:tablet_app/constants.dart'; -import 'puzzle_piece.dart'; - -const IMAGE_PATH = 'image_path'; - -class PuzzleView extends StatefulWidget { - final PuzzleDTO section; - PuzzleView({required this.section}); - - @override - _PuzzleView createState() => _PuzzleView(); -} - -class _PuzzleView extends State { - PuzzleDTO puzzleDTO = PuzzleDTO(); - - int allInPlaceCount = 0; - bool isFinished = false; - DateTime? _puzzleStartTime; - GlobalKey _widgetKey = GlobalKey(); - Size? realWidgetSize; - List pieces = []; - - bool isSplittingImage = true; - - @override - void initState() { - //puzzleDTO = PuzzleDTO.fromJson(jsonDecode(widget.section!.data!))!; - puzzleDTO = widget.section; - puzzleDTO.rows = puzzleDTO.rows != null ? puzzleDTO.rows : 3; - puzzleDTO.cols = puzzleDTO.cols != null ? puzzleDTO.cols : 3; - _puzzleStartTime = DateTime.now(); - - WidgetsBinding.instance.addPostFrameCallback((_) { - Size size = MediaQuery.of(context).size; - final appContext = Provider.of(context, listen: false); - TabletAppContext tabletAppContext = appContext.getContext(); - - print(puzzleDTO.messageDebut); - TranslationAndResourceDTO? messageDebut = puzzleDTO.messageDebut != null && puzzleDTO.messageDebut!.length > 0 ? puzzleDTO.messageDebut!.where((message) => message.language!.toUpperCase() == tabletAppContext.language!.toUpperCase()).firstOrNull : null; - - if(messageDebut != null) { - showMessage(messageDebut, appContext, context, size); - } - - getRealWidgetSize(); - - if(puzzleDTO.puzzleImage != null && puzzleDTO.puzzleImage!.url != null) { - //splitImage(Image.network(puzzleDTO.image!.resourceUrl!)); - splitImage(CachedNetworkImage( - imageUrl: puzzleDTO.puzzleImage!.url!, - fit: BoxFit.fill, - errorWidget: (context, url, error) => Icon(Icons.error), - )); - } else { - setState(() { - isSplittingImage = false; - }); - } - }); - - super.initState(); - } - - Future getRealWidgetSize() async { - RenderBox renderBox = _widgetKey.currentContext?.findRenderObject() as RenderBox; - Size size = renderBox.size; - - setState(() { - realWidgetSize = size; - }); - print("Taille réelle du widget : $size"); - } - - // we need to find out the image size, to be used in the PuzzlePiece widget - /*Future getImageSize(CachedNetworkImage image) async { - Completer completer = Completer(); - - /*image.image - .resolve(const ImageConfiguration()) - .addListener(ImageStreamListener((ImageInfo info, bool _) { - completer.complete( - Size(info.image.width.toDouble(), info.image.height.toDouble())); - }));*/ - - CachedNetworkImage( - imageUrl: 'https://example.com/image.jpg', - placeholder: (context, url) => CircularProgressIndicator(), - errorWidget: (context, url, error) => Icon(Icons.error), - imageBuilder: (BuildContext context, ImageProvider imageProvider) { - Completer completer = Completer(); - - imageProvider - .resolve(const ImageConfiguration()) - .addListener(ImageStreamListener((ImageInfo info, bool _) { - completer.complete( - Size(info.image.width.toDouble(), info.image.height.toDouble())); - })); - - return CachedNetworkImage( - imageUrl: 'https://example.com/image.jpg', - placeholder: (context, url) => CircularProgressIndicator(), - errorWidget: (context, url, error) => Icon(Icons.error), - imageBuilder: (context, imageProvider) { - return Image( - image: imageProvider, - loadingBuilder: (BuildContext context, Widget child, ImageChunkEvent? loadingProgress) { - if (loadingProgress == null) { - return child; - } else { - return Center( - child: CircularProgressIndicator( - value: loadingProgress.expectedTotalBytes != null - ? loadingProgress.cumulativeBytesLoaded / (loadingProgress.expectedTotalBytes ?? 1) - : null, - ), - ); - } - }, - ); - }, - ); - }, - ); - - Size imageSize = await completer.future; - - return imageSize; - }*/ - - // here we will split the image into small pieces - // using the rows and columns defined above; each piece will be added to a stack - void splitImage(CachedNetworkImage image) async { - //Size imageSize = await getImageSize(image); - //imageSize = realWidgetSize!; - Size imageSize = Size(realWidgetSize!.width * 1.25, realWidgetSize!.height * 1.25); - - for (int x = 0; x < puzzleDTO.rows!; x++) { - for (int y = 0; y < puzzleDTO.cols!; y++) { - setState(() { - pieces.add( - PuzzlePiece( - key: GlobalKey(), - image: image, - imageSize: imageSize, - row: x, - col: y, - maxRow: puzzleDTO.rows!, - maxCol: puzzleDTO.cols!, - bringToTop: this.bringToTop, - sendToBack: this.sendToBack, - ), - ); - }); - } - } - - setState(() { - isSplittingImage = false; - }); - } - - // when the pan of a piece starts, we need to bring it to the front of the stack - void bringToTop(Widget widget) { - setState(() { - pieces.remove(widget); - pieces.add(widget); - }); - } - -// when a piece reaches its final position, -// it will be sent to the back of the stack to not get in the way of other, still movable, pieces - void sendToBack(Widget widget) { - setState(() { - allInPlaceCount++; - isFinished = allInPlaceCount == puzzleDTO.rows! * puzzleDTO.cols!; - pieces.remove(widget); - pieces.insert(0, widget); - - if(isFinished) { - Size size = MediaQuery.of(context).size; - final appContext = Provider.of(context, listen: false); - TabletAppContext tabletAppContext = appContext.getContext(); - final duration = _puzzleStartTime != null ? DateTime.now().difference(_puzzleStartTime!).inSeconds : 0; - tabletAppContext.statisticsService?.track( - VisitEventType.gameComplete, - metadata: {'gameType': 'Puzzle', 'durationSeconds': duration}, - ); - TranslationAndResourceDTO? messageFin = puzzleDTO.messageFin != null && puzzleDTO.messageFin!.length > 0 ? puzzleDTO.messageFin!.where((message) => message.language!.toUpperCase() == tabletAppContext.language!.toUpperCase()).firstOrNull : null; - - if(messageFin != null) { - showMessage(messageFin, appContext, context, size); - } - } - }); - } - - @override - Widget build(BuildContext context) { - final appContext = Provider.of(context); - TabletAppContext tabletAppContext = appContext.getContext(); - - return Container( - //color: Colors.green, - child: Padding( - key: _widgetKey, - padding: const EdgeInsets.all(0.0), - child: isSplittingImage ? Center(child: LoadingCommon()) : - puzzleDTO.puzzleImage == null || puzzleDTO.puzzleImage!.url == null || realWidgetSize == null - ? Center(child: Text("Aucune image à afficher", style: TextStyle(fontSize: kNoneInfoOrIncorrect))) - : Center( - child: Padding( - padding: const EdgeInsets.all(0.0), - child: Container( - width: tabletAppContext.puzzleSize != null && tabletAppContext.puzzleSize!.width > 0 ? tabletAppContext.puzzleSize!.width : realWidgetSize!.width * 0.8, - height: tabletAppContext.puzzleSize != null && tabletAppContext.puzzleSize!.height > 0 ? tabletAppContext.puzzleSize!.height +1.5 : realWidgetSize!.height * 0.85, - child: Stack( - children: pieces, - ), - ), - ), - ), - ), - ); - } -} \ No newline at end of file diff --git a/lib/Screens/Quizz/quizz_view.dart b/lib/Screens/Quizz/quizz_view.dart index 16de175..7e967a3 100644 --- a/lib/Screens/Quizz/quizz_view.dart +++ b/lib/Screens/Quizz/quizz_view.dart @@ -151,7 +151,7 @@ class _QuizzView extends State { decoration: BoxDecoration( color: kBackgroundLight, shape: BoxShape.rectangle, - borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 10.0), + borderRadius: BorderRadius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 10.0), boxShadow: [ BoxShadow( color: kBackgroundSecondGrey, @@ -190,7 +190,7 @@ class _QuizzView extends State { decoration: BoxDecoration( color: kBackgroundLight, shape: BoxShape.rectangle, - borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 10.0), + borderRadius: BorderRadius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 10.0), boxShadow: [ BoxShadow( color: kBackgroundSecondGrey, @@ -290,7 +290,7 @@ class _QuizzView extends State { decoration: BoxDecoration( color: kBackgroundLight, shape: BoxShape.rectangle, - borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0), + borderRadius: BorderRadius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0), image: i.resourceUrl != null ? new DecorationImage( fit: BoxFit.cover, opacity: 0.35, @@ -322,7 +322,7 @@ class _QuizzView extends State { decoration: BoxDecoration( color: kBackgroundLight, // Colors.orange,// kBackgroundLight, shape: BoxShape.rectangle, - borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 10.0), + borderRadius: BorderRadius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 10.0), boxShadow: [ BoxShadow( color: kBackgroundSecondGrey, @@ -457,7 +457,7 @@ class _QuizzView extends State { decoration: BoxDecoration( color: i.chosen == index ? primaryColor : kBackgroundLight, shape: BoxShape.rectangle, - borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 10.0), + borderRadius: BorderRadius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 10.0), boxShadow: [ BoxShadow( color: kBackgroundSecondGrey, @@ -563,13 +563,13 @@ getElementForResource(BuildContext context, AppContext appContext, TranslationAn builder: (BuildContext context) { return AlertDialog( shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)) + borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0)) ), contentPadding: EdgeInsets.zero, // title: Text(eventAgenda.name!), content: Container( decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)), + borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0)), color: kBackgroundColor, ), height: size.height * 0.8, @@ -577,7 +577,7 @@ getElementForResource(BuildContext context, AppContext appContext, TranslationAn child: Container( decoration: BoxDecoration( color: const Color(0xff7c94b6), - borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 15.0)), + borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 15.0)), ), child: PhotoView( imageProvider: ImageCustomProvider.getImageProvider(appContext, i.resourceId!, i.resource!.url!), @@ -586,7 +586,7 @@ getElementForResource(BuildContext context, AppContext appContext, TranslationAn backgroundDecoration: BoxDecoration( color: kBackgroundSecondGrey, shape: BoxShape.rectangle, - borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 15.0), + borderRadius: BorderRadius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 15.0), ), ), ), @@ -603,7 +603,7 @@ getElementForResource(BuildContext context, AppContext appContext, TranslationAn image: ImageCustomProvider.getImageProvider(appContext, i.resourceId!, i.resource!.url!), fit: BoxFit.contain, ), - borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 15.0)), + borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 15.0)), /*border: Border.all( color: kBackgroundGrey, width: 1.0, @@ -624,13 +624,13 @@ getElementForResource(BuildContext context, AppContext appContext, TranslationAn builder: (BuildContext context) { return AlertDialog( shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)) + borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0)) ), contentPadding: EdgeInsets.zero, // title: Text(eventAgenda.name!), content: Container( decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)), + borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0)), color: kBackgroundColor, ), height: size.height * 0.8, @@ -648,7 +648,7 @@ getElementForResource(BuildContext context, AppContext appContext, TranslationAn decoration: BoxDecoration( //color: kBackgroundSecondGrey, shape: BoxShape.rectangle, - borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 15.0), + borderRadius: BorderRadius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 15.0), ), child: showElementForResource(ResourceDTO(id: i.resourceId, url: i.resource!.url, type: i.resource!.type), appContext, false, true), ), diff --git a/lib/Screens/Quizz/showResponses.dart b/lib/Screens/Quizz/showResponses.dart index 9347250..1f3a2b5 100644 --- a/lib/Screens/Quizz/showResponses.dart +++ b/lib/Screens/Quizz/showResponses.dart @@ -81,7 +81,7 @@ class _ShowReponsesWidget extends State { decoration: BoxDecoration( color: kBackgroundLight, shape: BoxShape.rectangle, - borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0), + borderRadius: BorderRadius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0), image: i.resourceUrl != null ? new DecorationImage( fit: BoxFit.contain, opacity: 0.35, @@ -113,7 +113,7 @@ class _ShowReponsesWidget extends State { decoration: BoxDecoration( color: kBackgroundLight, shape: BoxShape.rectangle, - borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 10.0), + borderRadius: BorderRadius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 10.0), boxShadow: [ BoxShadow( color: kBackgroundSecondGrey, @@ -177,7 +177,7 @@ class _ShowReponsesWidget extends State { decoration: BoxDecoration( color: i.responsesSubDTO![index].isGood! ? kGreen : i.chosen == index ? kMainRed : kBackgroundLight, shape: BoxShape.rectangle, - borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 10.0), + borderRadius: BorderRadius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 10.0), boxShadow: [ BoxShadow( color: kBackgroundSecondGrey, diff --git a/lib/Screens/Slider/slider_view.dart b/lib/Screens/Slider/slider_view.dart index 317c9af..05b6631 100644 --- a/lib/Screens/Slider/slider_view.dart +++ b/lib/Screens/Slider/slider_view.dart @@ -79,7 +79,7 @@ class _SliderView extends State { margin: EdgeInsets.symmetric(horizontal: 5.0), decoration: BoxDecoration( //color: configurationDTO.imageId == null ? configurationDTO.secondaryColor != null ? new Color(int.parse(configurationDTO.secondaryColor!.split('(0x')[1].split(')')[0], radix: 16)): kBackgroundGrey : null, - borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 10.0), + borderRadius: BorderRadius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 10.0), //border: Border.all(width: 0.3, color: kSecondGrey), ), child: Column( @@ -137,7 +137,7 @@ class _SliderView extends State { decoration: BoxDecoration( color: kBackgroundLight, shape: BoxShape.rectangle, - borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 10.0), + borderRadius: BorderRadius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 10.0), boxShadow: [ BoxShadow( color: kBackgroundSecondGrey, @@ -265,7 +265,7 @@ class _SliderView extends State { backgroundDecoration: BoxDecoration( color: kBackgroundSecondGrey, shape: BoxShape.rectangle, - borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 15.0), + borderRadius: BorderRadius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 15.0), ), ); break; @@ -277,7 +277,7 @@ class _SliderView extends State { backgroundDecoration: BoxDecoration( color: kBackgroundSecondGrey, shape: BoxShape.rectangle, - borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 15.0), + borderRadius: BorderRadius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 15.0), ), ); break; @@ -288,7 +288,7 @@ class _SliderView extends State { decoration: BoxDecoration( //color: kBackgroundSecondGrey, //shape: BoxShape.rectangle, - borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 15.0), + borderRadius: BorderRadius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 15.0), ), child: showElementForResource(ResourceDTO(id: i.resourceId, url: i.resource!.url, type: i.resource!.type), appContext, false, true), ); diff --git a/lib/Screens/Weather/weather_view.dart b/lib/Screens/Weather/weather_view.dart index 9c54373..fcd45c9 100644 --- a/lib/Screens/Weather/weather_view.dart +++ b/lib/Screens/Weather/weather_view.dart @@ -149,7 +149,7 @@ class _WeatherViewState extends State { return weatherData == null ? Center(child: Text("Aucune donnée à afficher")) : Container( decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)), + borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0)), gradient: LinearGradient( begin: Alignment.topRight, end: Alignment.bottomLeft, @@ -229,7 +229,7 @@ class _WeatherViewState extends State { height: size.height * 0.25, width: size.width * 0.6, decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)), + borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0)), //color: Colors.grey, ), child: Column( @@ -251,7 +251,7 @@ class _WeatherViewState extends State { height: size.height * 0.15, width: size.width * 0.1, decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)), + borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0)), color: Colors.lightBlueAccent, boxShadow: [ BoxShadow( @@ -286,7 +286,7 @@ class _WeatherViewState extends State { height: size.height * 0.3, width: size.width * 0.75, decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)), + borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0)), //color: Colors.amber, ), child: Column( @@ -308,7 +308,7 @@ class _WeatherViewState extends State { height: size.height * 0.22, width: size.width * 0.125, decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)), + borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0)), color: Colors.lightBlue, boxShadow: [ BoxShadow(