172 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
			
		
		
	
	
			172 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
import 'dart:collection';
 | 
						|
import 'dart:convert';
 | 
						|
 | 
						|
import 'package:flutter/material.dart';
 | 
						|
import 'package:shared_preferences/shared_preferences.dart';
 | 
						|
 | 
						|
LandmarkType typeSightseeing = LandmarkType(name: 'sightseeing');
 | 
						|
LandmarkType typeNature = LandmarkType(name: 'nature');
 | 
						|
LandmarkType typeShopping = LandmarkType(name: 'shopping');
 | 
						|
// LandmarkType museum = LandmarkType(name: 'Museum');
 | 
						|
// LandmarkType restaurant = LandmarkType(name: 'Restaurant');
 | 
						|
LandmarkType typeStart = LandmarkType(name: 'start');
 | 
						|
LandmarkType typeFinish = LandmarkType(name: 'finish');
 | 
						|
 | 
						|
 | 
						|
final class Landmark extends LinkedListEntry<Landmark>{
 | 
						|
  // A linked node of a list of Landmarks
 | 
						|
  final String uuid;
 | 
						|
  final String name;
 | 
						|
  final List<double> location;
 | 
						|
  final LandmarkType type;
 | 
						|
  final bool? isSecondary;
 | 
						|
 | 
						|
  // description to be shown in the overview
 | 
						|
  final String? nameEN;
 | 
						|
  final String? websiteURL;
 | 
						|
  String? imageURL; // not final because it can be patched
 | 
						|
  final String? description;
 | 
						|
  final Duration? duration;
 | 
						|
  final bool? visited;
 | 
						|
 | 
						|
  // Next node
 | 
						|
  // final Landmark? next;
 | 
						|
  final Duration? tripTime;
 | 
						|
 | 
						|
 | 
						|
  Landmark({
 | 
						|
    required this.uuid,
 | 
						|
    required this.name,
 | 
						|
    required this.location,
 | 
						|
    required this.type,
 | 
						|
    this.isSecondary,
 | 
						|
 | 
						|
    this.nameEN,
 | 
						|
    this.websiteURL,
 | 
						|
    this.imageURL,
 | 
						|
    this.description,
 | 
						|
    this.duration,
 | 
						|
    this.visited,
 | 
						|
 | 
						|
    // this.next,
 | 
						|
    this.tripTime,
 | 
						|
  });
 | 
						|
 | 
						|
 | 
						|
  factory Landmark.fromJson(Map<String, dynamic> json) {
 | 
						|
    if (json
 | 
						|
      case { // automatically match all the non-optionals and cast them to the right type
 | 
						|
        'uuid': String uuid,
 | 
						|
        'name': String name,
 | 
						|
        'location': List<dynamic> location,
 | 
						|
        'type': String type,
 | 
						|
      }) {
 | 
						|
      // refine the parsing on a few fields
 | 
						|
      List<double> locationFixed = List<double>.from(location);
 | 
						|
      // 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 imageURL = json['image_url'] as String?;
 | 
						|
      final description = json['description'] as String?;
 | 
						|
      var duration = Duration(minutes: json['duration'] ?? 0) as Duration?;
 | 
						|
      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,
 | 
						|
        nameEN: nameEN,
 | 
						|
        websiteURL: websiteURL,
 | 
						|
        imageURL: imageURL,
 | 
						|
        description: description,
 | 
						|
        duration: duration,
 | 
						|
        visited: visited,
 | 
						|
        tripTime: tripTime
 | 
						|
      );
 | 
						|
    } else {
 | 
						|
      throw FormatException('Invalid JSON: $json');
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  @override
 | 
						|
  bool operator ==(Object other) {
 | 
						|
    return other is Landmark && uuid == other.uuid;
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  Map<String, dynamic> toJson() => {
 | 
						|
    'uuid': uuid,
 | 
						|
    'name': name,
 | 
						|
    'location': location,
 | 
						|
    'type': type.name,
 | 
						|
    'is_secondary': isSecondary,
 | 
						|
    'name_en': nameEN,
 | 
						|
    'website_url': websiteURL,
 | 
						|
    'image_url': imageURL,
 | 
						|
    'description': description,
 | 
						|
    'duration': duration?.inMinutes,
 | 
						|
    'visited': visited,
 | 
						|
    'trip_time': tripTime?.inMinutes,
 | 
						|
  };
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
class LandmarkType {
 | 
						|
  final String name;
 | 
						|
  // final String description;
 | 
						|
  Icon icon;
 | 
						|
  
 | 
						|
  LandmarkType({required this.name, this.icon = const Icon(Icons.location_on)}) {
 | 
						|
    switch (name) {
 | 
						|
      case 'sightseeing':
 | 
						|
        icon = const Icon(Icons.castle);
 | 
						|
        break;
 | 
						|
      case 'nature':
 | 
						|
        icon = const Icon(Icons.eco);
 | 
						|
        break;
 | 
						|
      case 'shopping':
 | 
						|
        icon = const Icon(Icons.shopping_cart);
 | 
						|
        break;
 | 
						|
      case 'start':
 | 
						|
        icon = const Icon(Icons.play_arrow);
 | 
						|
        break;
 | 
						|
      case 'finish':
 | 
						|
        icon = const Icon(Icons.flag);
 | 
						|
        break;
 | 
						|
      default:
 | 
						|
        icon = const Icon(Icons.location_on);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  @override
 | 
						|
  bool operator ==(Object other) {
 | 
						|
    if (other is LandmarkType) {
 | 
						|
      return name == other.name;
 | 
						|
    } else {
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// Helpers
 | 
						|
// Handling the landmarks requires a little bit of special care because the linked list is not directly representable in json
 | 
						|
(Landmark, String?) getLandmarkFromPrefs(SharedPreferences prefs, String uuid) {
 | 
						|
  String? content = prefs.getString('landmark_$uuid');
 | 
						|
  Map<String, dynamic> json = jsonDecode(content!);
 | 
						|
  String? nextUUID = json['next_uuid'];
 | 
						|
  return (Landmark.fromJson(json), nextUUID);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void landmarkToPrefs(SharedPreferences prefs, Landmark current, Landmark? next) {
 | 
						|
  Map<String, dynamic> json = current.toJson();
 | 
						|
  json['next_uuid'] = next?.uuid;
 | 
						|
  prefs.setString('landmark_${current.uuid}', jsonEncode(json));
 | 
						|
}
 |