display more landmark information #21
| @@ -1,9 +1,9 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:cached_network_image/cached_network_image.dart'; | ||||
| import 'package:url_launcher/url_launcher.dart'; | ||||
|  | ||||
| import 'package:anyway/structs/landmark.dart'; | ||||
|  | ||||
|  | ||||
| class LandmarkCard extends StatefulWidget { | ||||
|   final Landmark landmark; | ||||
|    | ||||
| @@ -18,6 +18,10 @@ class _LandmarkCardState extends State<LandmarkCard> { | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     ThemeData theme = Theme.of(context); | ||||
|     ButtonStyle buttonStyle = TextButton.styleFrom( | ||||
|       backgroundColor: Colors.orange, | ||||
|       fixedSize: Size.fromHeight(20) | ||||
|     ); | ||||
|     return Container( | ||||
|       height: 160, | ||||
|       child: Card( | ||||
| @@ -62,15 +66,62 @@ class _LandmarkCardState extends State<LandmarkCard> { | ||||
|                         ) | ||||
|                       ], | ||||
|                     ), | ||||
|                     Row( | ||||
|                       children: [ | ||||
|                         Flexible( | ||||
|                           child: Text( | ||||
|                             "${widget.landmark.name} (${widget.landmark.type.name})", | ||||
|                             style: const TextStyle(fontSize: 14), | ||||
|                     if (widget.landmark.nameEN != null) | ||||
|                       Row( | ||||
|                         children: [ | ||||
|                           Flexible( | ||||
|                             child: Text( | ||||
|                               widget.landmark.nameEN!, | ||||
|                               style: const TextStyle( | ||||
|                                 fontSize: 16, | ||||
|                               ), | ||||
|                               maxLines: 1, | ||||
|                             ), | ||||
|                           ) | ||||
|                         ], | ||||
|                       ), | ||||
|                     SingleChildScrollView( | ||||
|                       // allows the buttons to be scrolled | ||||
|                       scrollDirection: Axis.horizontal, | ||||
|                       child: Wrap( | ||||
|                         spacing: 10, | ||||
|                         // show the type, the website, and the wikipedia link as buttons/labels in a row | ||||
|                         children: [ | ||||
|                           TextButton.icon( | ||||
|                             style: buttonStyle, | ||||
|                             onPressed: () {}, | ||||
|                             icon: widget.landmark.type.icon, | ||||
|                             label: Text(widget.landmark.type.name), | ||||
|                           ), | ||||
|                         ) | ||||
|                       ] | ||||
|                           if (widget.landmark.duration != null && widget.landmark.duration!.inMinutes > 0) | ||||
|                             TextButton.icon( | ||||
|                               style: buttonStyle, | ||||
|                               onPressed: () {}, | ||||
|                               icon: Icon(Icons.hourglass_bottom), | ||||
|                               label: Text('${widget.landmark.duration!.inMinutes} minutes'), | ||||
|                             ), | ||||
|                           if (widget.landmark.websiteURL != null) | ||||
|                             TextButton.icon( | ||||
|                               style: buttonStyle, | ||||
|                               onPressed: () async { | ||||
|                                 // open a browser with the website link | ||||
|                                 await launchUrl(Uri.parse(widget.landmark.websiteURL!)); | ||||
|                               }, | ||||
|                               icon: Icon(Icons.link), | ||||
|                               label: Text('Website'), | ||||
|                             ), | ||||
|                           if (widget.landmark.wikipediaURL != null) | ||||
|                             TextButton.icon( | ||||
|                               style: buttonStyle, | ||||
|                               onPressed: () async { | ||||
|                                 // open a browser with the wikipedia link | ||||
|                                 await launchUrl(Uri.parse(widget.landmark.wikipediaURL!)); | ||||
|                               }, | ||||
|                               icon: Icon(Icons.book), | ||||
|                             label: Text('Wikipedia'), | ||||
|                           ), | ||||
|                         ], | ||||
|                       ), | ||||
|                     ), | ||||
|                   ], | ||||
|                 ), | ||||
|   | ||||
| @@ -1,15 +1,16 @@ | ||||
| import 'dart:collection'; | ||||
| import 'dart:convert'; | ||||
|  | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:shared_preferences/shared_preferences.dart'; | ||||
|  | ||||
| const LandmarkType sightseeing = LandmarkType(name: 'sightseeing'); | ||||
| const LandmarkType nature = LandmarkType(name: 'nature'); | ||||
| const LandmarkType shopping = LandmarkType(name: 'shopping'); | ||||
| // const LandmarkType museum = LandmarkType(name: 'Museum'); | ||||
| // const LandmarkType restaurant = LandmarkType(name: 'Restaurant'); | ||||
| const LandmarkType start = LandmarkType(name: 'start'); | ||||
| const LandmarkType finish = LandmarkType(name: 'finish'); | ||||
| LandmarkType sightseeing = LandmarkType(name: 'sightseeing'); | ||||
| LandmarkType nature = LandmarkType(name: 'nature'); | ||||
| LandmarkType shopping = LandmarkType(name: 'shopping'); | ||||
| // LandmarkType museum = LandmarkType(name: 'Museum'); | ||||
| // LandmarkType restaurant = LandmarkType(name: 'Restaurant'); | ||||
| LandmarkType start = LandmarkType(name: 'start'); | ||||
| LandmarkType finish = LandmarkType(name: 'finish'); | ||||
|  | ||||
|  | ||||
| final class Landmark extends LinkedListEntry<Landmark>{ | ||||
| @@ -21,6 +22,9 @@ final class Landmark extends LinkedListEntry<Landmark>{ | ||||
|   final bool? isSecondary; | ||||
|  | ||||
|   // description to be shown in the overview | ||||
|   final String? nameEN; | ||||
|   final String? websiteURL; | ||||
|   final String? wikipediaURL; | ||||
|   final String? imageURL; | ||||
|   final String? description; | ||||
|   final Duration? duration; | ||||
| @@ -38,6 +42,9 @@ final class Landmark extends LinkedListEntry<Landmark>{ | ||||
|     required this.type, | ||||
|     this.isSecondary, | ||||
|  | ||||
|     this.nameEN, | ||||
|     this.websiteURL, | ||||
|     this.wikipediaURL, | ||||
|     this.imageURL, | ||||
|     this.description, | ||||
|     this.duration, | ||||
| @@ -61,15 +68,30 @@ final class Landmark extends LinkedListEntry<Landmark>{ | ||||
|       // parse the rest separately, they could be missing | ||||
|       LandmarkType typeFixed = LandmarkType(name: type); | ||||
|       final isSecondary = json['is_secondary'] as bool?; | ||||
|       final nameEN = json['name_en'] as String?; | ||||
|       final websiteURL = json['website_url'] as String?; | ||||
|       final wikipediaURL = json['wikipedia_url'] as String?; | ||||
|       final imageURL = json['image_url'] as String?; | ||||
|       final description = json['description'] as String?; | ||||
|       var duration = Duration(minutes: json['duration'] ?? 0) as Duration?; | ||||
|       // if (duration == const Duration()) {duration = null;}; | ||||
|       final visited = json['visited'] as bool?; | ||||
|       var tripTime = Duration(minutes: json['time_to_reach_next'] ?? 0) as Duration?; | ||||
|        | ||||
|       return Landmark( | ||||
|         uuid: uuid, name: name, location: locationFixed, type: typeFixed, isSecondary: isSecondary, imageURL: imageURL, description: description, duration: duration, visited: visited, tripTime: tripTime); | ||||
|         uuid: uuid, | ||||
|         name: name, | ||||
|         location: locationFixed, | ||||
|         type: typeFixed, | ||||
|         isSecondary: isSecondary, | ||||
|         nameEN: nameEN, | ||||
|         websiteURL: websiteURL, | ||||
|         wikipediaURL: wikipediaURL, | ||||
|         imageURL: imageURL, | ||||
|         description: description, | ||||
|         duration: duration, | ||||
|         visited: visited, | ||||
|         tripTime: tripTime | ||||
|       ); | ||||
|     } else { | ||||
|       throw FormatException('Invalid JSON: $json'); | ||||
|     } | ||||
| @@ -88,6 +110,9 @@ final class Landmark extends LinkedListEntry<Landmark>{ | ||||
|     'location': location, | ||||
|     'type': type.name, | ||||
|     'is_secondary': isSecondary, | ||||
|     'name_en': nameEN, | ||||
|     'website_url': websiteURL, | ||||
|     'wikipedia_url': wikipediaURL, | ||||
|     'image_url': imageURL, | ||||
|     'description': description, | ||||
|     'duration': duration?.inMinutes, | ||||
| @@ -100,13 +125,29 @@ final class Landmark extends LinkedListEntry<Landmark>{ | ||||
| class LandmarkType { | ||||
|   final String name; | ||||
|   // final String description; | ||||
|   // final Icon icon; | ||||
|   Icon icon; | ||||
|    | ||||
|   const LandmarkType({ | ||||
|     required this.name, | ||||
|     // required this.description, | ||||
|     // required this.icon, | ||||
|   }); | ||||
|   LandmarkType({required this.name, this.icon = const Icon(Icons.location_on)}) { | ||||
|     switch (name) { | ||||
|       case 'sightseeing': | ||||
|         icon = Icon(Icons.church); | ||||
|         break; | ||||
|       case 'nature': | ||||
|         icon = Icon(Icons.eco); | ||||
|         break; | ||||
|       case 'shopping': | ||||
|         icon = Icon(Icons.shopping_cart); | ||||
|         break; | ||||
|       case 'start': | ||||
|         icon = Icon(Icons.play_arrow); | ||||
|         break; | ||||
|       case 'finish': | ||||
|         icon = Icon(Icons.flag); | ||||
|         break; | ||||
|       default: | ||||
|         icon = Icon(Icons.location_on); | ||||
|     } | ||||
|   } | ||||
|   @override | ||||
|   bool operator ==(Object other) { | ||||
|     if (other is LandmarkType) { | ||||
|   | ||||
| @@ -6,6 +6,10 @@ | ||||
|  | ||||
| #include "generated_plugin_registrant.h" | ||||
|  | ||||
| #include <url_launcher_linux/url_launcher_plugin.h> | ||||
|  | ||||
| void fl_register_plugins(FlPluginRegistry* registry) { | ||||
|   g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = | ||||
|       fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); | ||||
|   url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); | ||||
| } | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
| # | ||||
|  | ||||
| list(APPEND FLUTTER_PLUGIN_LIST | ||||
|   url_launcher_linux | ||||
| ) | ||||
|  | ||||
| list(APPEND FLUTTER_FFI_PLUGIN_LIST | ||||
|   | ||||
| @@ -8,9 +8,11 @@ import Foundation | ||||
| import path_provider_foundation | ||||
| import shared_preferences_foundation | ||||
| import sqflite | ||||
| import url_launcher_macos | ||||
|  | ||||
| func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { | ||||
|   PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) | ||||
|   SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) | ||||
|   SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) | ||||
|   UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) | ||||
| } | ||||
|   | ||||
| @@ -661,6 +661,70 @@ packages: | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "1.3.2" | ||||
|   url_launcher: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: url_launcher | ||||
|       sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "6.3.0" | ||||
|   url_launcher_android: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: url_launcher_android | ||||
|       sha256: e35a698ac302dd68e41f73250bd9517fe3ab5fa4f18fe4647a0872db61bacbab | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "6.3.10" | ||||
|   url_launcher_ios: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: url_launcher_ios | ||||
|       sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "6.3.1" | ||||
|   url_launcher_linux: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: url_launcher_linux | ||||
|       sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "3.2.0" | ||||
|   url_launcher_macos: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: url_launcher_macos | ||||
|       sha256: "9a1a42d5d2d95400c795b2914c36fdcb525870c752569438e4ebb09a2b5d90de" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "3.2.0" | ||||
|   url_launcher_platform_interface: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: url_launcher_platform_interface | ||||
|       sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.3.2" | ||||
|   url_launcher_web: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: url_launcher_web | ||||
|       sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.3.3" | ||||
|   url_launcher_windows: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: url_launcher_windows | ||||
|       sha256: "49c10f879746271804767cb45551ec5592cdab00ee105c06dddde1a98f73b185" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "3.1.2" | ||||
|   uuid: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -705,10 +769,10 @@ packages: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: vm_service | ||||
|       sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc | ||||
|       sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "14.2.4" | ||||
|     version: "14.2.5" | ||||
|   web: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -742,5 +806,5 @@ packages: | ||||
|     source: hosted | ||||
|     version: "6.5.0" | ||||
| sdks: | ||||
|   dart: ">=3.4.0 <4.0.0" | ||||
|   flutter: ">=3.22.0" | ||||
|   dart: ">=3.5.0 <4.0.0" | ||||
|   flutter: ">=3.24.0" | ||||
|   | ||||
| @@ -47,6 +47,7 @@ dependencies: | ||||
|   auto_size_text: ^3.0.0 | ||||
|   map_launcher: ^3.3.1 | ||||
|   flutter_svg: ^2.0.10+1 | ||||
|   url_launcher: ^6.3.0 | ||||
|  | ||||
| dev_dependencies: | ||||
|   flutter_test: | ||||
|   | ||||
| @@ -6,6 +6,9 @@ | ||||
|  | ||||
| #include "generated_plugin_registrant.h" | ||||
|  | ||||
| #include <url_launcher_windows/url_launcher_windows.h> | ||||
|  | ||||
| void RegisterPlugins(flutter::PluginRegistry* registry) { | ||||
|   UrlLauncherWindowsRegisterWithRegistrar( | ||||
|       registry->GetRegistrarForPlugin("UrlLauncherWindows")); | ||||
| } | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
| # | ||||
|  | ||||
| list(APPEND FLUTTER_PLUGIN_LIST | ||||
|   url_launcher_windows | ||||
| ) | ||||
|  | ||||
| list(APPEND FLUTTER_FFI_PLUGIN_LIST | ||||
|   | ||||
		Reference in New Issue
	
	Block a user