Frontend UX improvements #37
							
								
								
									
										111
									
								
								backend/test.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								backend/test.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,111 @@
 | 
				
			|||||||
 | 
					import numpy as np
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def euclidean_distance(p1, p2):
 | 
				
			||||||
 | 
					    print(p1, p2)
 | 
				
			||||||
 | 
					    return np.sqrt((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def maximize_score(places, max_distance, fixed_entry, top_k=3):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Maximizes the total score of visited places while staying below the maximum distance.
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    Parameters:
 | 
				
			||||||
 | 
					    places (list of tuples): Each tuple contains (score, (x, y), location).
 | 
				
			||||||
 | 
					    max_distance (float): The maximum distance that can be traveled.
 | 
				
			||||||
 | 
					    fixed_entry (tuple): The place that needs to be visited independently of its score.
 | 
				
			||||||
 | 
					    top_k (int): Number of top candidates to consider in each iteration.
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    Returns:
 | 
				
			||||||
 | 
					    list of tuples: The visited places.
 | 
				
			||||||
 | 
					    float: The total score of the visited places.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    # Initialize total distance and score
 | 
				
			||||||
 | 
					    total_distance = 0
 | 
				
			||||||
 | 
					    total_score = 0
 | 
				
			||||||
 | 
					    visited_places = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Add the fixed entry to the visited list
 | 
				
			||||||
 | 
					    score, (x, y), _ = fixed_entry
 | 
				
			||||||
 | 
					    visited_places.append(fixed_entry)
 | 
				
			||||||
 | 
					    total_score += score
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Remove the fixed entry from the list of places
 | 
				
			||||||
 | 
					    remaining_places = [place for place in places if place != fixed_entry]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Sort remaining places by score-to-distance ratio
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    remaining_places.sort(key=lambda p: p[0] / euclidean_distance((x, y), (p[1][0], p[1][1])), reverse=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Add places to the visited list if they don't exceed the maximum distance
 | 
				
			||||||
 | 
					    current_location = (x, y)
 | 
				
			||||||
 | 
					    while remaining_places and total_distance < max_distance:
 | 
				
			||||||
 | 
					        # Consider top_k candidates
 | 
				
			||||||
 | 
					        candidates = remaining_places[:top_k]
 | 
				
			||||||
 | 
					        best_candidate = None
 | 
				
			||||||
 | 
					        best_score_increase = -np.inf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for candidate in candidates:
 | 
				
			||||||
 | 
					            score, (cx, cy), location = candidate
 | 
				
			||||||
 | 
					            distance = euclidean_distance(current_location, (cx, cy))
 | 
				
			||||||
 | 
					            if total_distance + distance <= max_distance:
 | 
				
			||||||
 | 
					                score_increase = score / distance
 | 
				
			||||||
 | 
					                if score_increase > best_score_increase:
 | 
				
			||||||
 | 
					                    best_score_increase = score_increase
 | 
				
			||||||
 | 
					                    best_candidate = candidate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if best_candidate:
 | 
				
			||||||
 | 
					            visited_places.append(best_candidate)
 | 
				
			||||||
 | 
					            total_distance += euclidean_distance(current_location, best_candidate[1])
 | 
				
			||||||
 | 
					            total_score += best_candidate[0]
 | 
				
			||||||
 | 
					            current_location = best_candidate[1]
 | 
				
			||||||
 | 
					            remaining_places.remove(best_candidate)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return visited_places, total_score
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Example usage
 | 
				
			||||||
 | 
					places = [
 | 
				
			||||||
 | 
					    (10, (0, 0), 'A'),
 | 
				
			||||||
 | 
					    (8, (4, 2), 'B'),
 | 
				
			||||||
 | 
					    (15, (6, 4), 'C'),
 | 
				
			||||||
 | 
					    (7, (5, 6), 'D'),
 | 
				
			||||||
 | 
					    (12, (1, 8), 'E'),
 | 
				
			||||||
 | 
					    (14, (34, 10), 'F'),
 | 
				
			||||||
 | 
					    (15, (65, 12), 'G'),
 | 
				
			||||||
 | 
					    (12, (3, 14), 'H'),
 | 
				
			||||||
 | 
					    (12, (15, 1), 'I'),
 | 
				
			||||||
 | 
					    (7, (17, 4), 'J'),
 | 
				
			||||||
 | 
					    (12, (3, 3), 'K'),
 | 
				
			||||||
 | 
					    (4, (21, 22), 'L'),
 | 
				
			||||||
 | 
					    (12, (23, 24), 'M'),
 | 
				
			||||||
 | 
					    (4, (25, 26), 'N'),
 | 
				
			||||||
 | 
					    (2, (27, 28), 'O'),
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					fixed_entry = (10, (0, 0), 'A')
 | 
				
			||||||
 | 
					max_distance = 50
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					visited_places, total_score = maximize_score(places, max_distance, fixed_entry)
 | 
				
			||||||
 | 
					print("Visited Places:", visited_places)
 | 
				
			||||||
 | 
					print("Total Score:", total_score)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import matplotlib.pyplot as plt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Plot the route
 | 
				
			||||||
 | 
					def plot_route(visited_places):
 | 
				
			||||||
 | 
					    x_coords = [place[1][0] for place in visited_places]
 | 
				
			||||||
 | 
					    y_coords = [place[1][1] for place in visited_places]
 | 
				
			||||||
 | 
					    labels = [place[2] for place in visited_places]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    plt.figure(figsize=(10, 6))
 | 
				
			||||||
 | 
					    plt.plot(x_coords, y_coords, marker='o', linestyle='-', color='b')
 | 
				
			||||||
 | 
					    for i, label in enumerate(labels):
 | 
				
			||||||
 | 
					        plt.text(x_coords[i], y_coords[i], label, fontsize=12, ha='right')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    plt.title('Route of Visited Places')
 | 
				
			||||||
 | 
					    plt.xlabel('X Coordinate')
 | 
				
			||||||
 | 
					    plt.ylabel('Y Coordinate')
 | 
				
			||||||
 | 
					    plt.grid(True)
 | 
				
			||||||
 | 
					    plt.savefig('route.png')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					plot_route(visited_places)
 | 
				
			||||||
@@ -1,11 +1,20 @@
 | 
				
			|||||||
import 'dart:ui';
 | 
					import 'package:anyway/constants.dart';
 | 
				
			||||||
 | 
					 | 
				
			||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
import 'package:auto_size_text/auto_size_text.dart';
 | 
					import 'package:auto_size_text/auto_size_text.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'package:anyway/structs/trip.dart';
 | 
					import 'package:anyway/structs/trip.dart';
 | 
				
			||||||
import 'package:anyway/pages/current_trip.dart';
 | 
					import 'package:anyway/pages/current_trip.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					final List<String> statusTexts = [
 | 
				
			||||||
 | 
					  'Parsing your preferences...',
 | 
				
			||||||
 | 
					  'Finding the best places...',
 | 
				
			||||||
 | 
					  'Crunching the numbers...',
 | 
				
			||||||
 | 
					  'Calculating the best route...',
 | 
				
			||||||
 | 
					  'Making sure you have a great time...',
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CurrentTripLoadingIndicator extends StatefulWidget {
 | 
					class CurrentTripLoadingIndicator extends StatefulWidget {
 | 
				
			||||||
  final Trip trip;
 | 
					  final Trip trip;
 | 
				
			||||||
  const CurrentTripLoadingIndicator({
 | 
					  const CurrentTripLoadingIndicator({
 | 
				
			||||||
@@ -18,14 +27,52 @@ class CurrentTripLoadingIndicator extends StatefulWidget {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Widget bottomLoadingIndicator = Container(
 | 
					class _CurrentTripLoadingIndicatorState extends State<CurrentTripLoadingIndicator> {
 | 
				
			||||||
  height: 20.0, // Increase the height to take up more vertical space
 | 
					  @override
 | 
				
			||||||
 | 
					  Widget build(BuildContext context) => Stack(
 | 
				
			||||||
 | 
					    fit: StackFit.expand,
 | 
				
			||||||
 | 
					    children: [
 | 
				
			||||||
 | 
					      // In the very center of the panel, show the greeter which tells the user that the trip is being generated
 | 
				
			||||||
 | 
					      Center(child: loadingText(widget.trip)),
 | 
				
			||||||
 | 
					      // As a gimmick, and a way to show that the app is still working, show a few loading dots
 | 
				
			||||||
 | 
					      Align(
 | 
				
			||||||
 | 
					        alignment: Alignment.bottomCenter,
 | 
				
			||||||
 | 
					        child: statusText(),
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// automatically cycle through the greeter texts
 | 
				
			||||||
 | 
					class statusText extends StatefulWidget {
 | 
				
			||||||
 | 
					  const statusText({Key? key}) : super(key: key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  _statusTextState createState() => _statusTextState();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class _statusTextState extends State<statusText> {
 | 
				
			||||||
 | 
					  int statusIndex = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  void initState() {
 | 
				
			||||||
 | 
					    super.initState();
 | 
				
			||||||
 | 
					    Future.delayed(Duration(seconds: 5), () {
 | 
				
			||||||
 | 
					      setState(() {
 | 
				
			||||||
 | 
					        statusIndex = (statusIndex + 1) % statusTexts.length;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
 | 
					    return AutoSizeText(
 | 
				
			||||||
 | 
					      statusTexts[statusIndex],
 | 
				
			||||||
 | 
					      style: Theme.of(context).textTheme.labelSmall,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  child: ImageFiltered(
 | 
					 | 
				
			||||||
    imageFilter: ImageFilter.blur(sigmaX: 5.0, sigmaY: 5.0), // Apply blur effect
 | 
					 | 
				
			||||||
    child: Padding(padding: EdgeInsets.all(10), child: CircularProgressIndicator(),)
 | 
					 | 
				
			||||||
    ),
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Widget loadingText(Trip trip) => FutureBuilder(
 | 
					Widget loadingText(Trip trip) => FutureBuilder(
 | 
				
			||||||
@@ -34,22 +81,19 @@ Widget loadingText(Trip trip) => FutureBuilder(
 | 
				
			|||||||
    Widget greeter;
 | 
					    Widget greeter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (snapshot.hasData) {
 | 
					    if (snapshot.hasData) {
 | 
				
			||||||
      greeter = AutoSizeText(
 | 
					      greeter = AnimatedGradientText(
 | 
				
			||||||
        maxLines: 1,
 | 
					        text: 'Creating your trip to ${snapshot.data}...',
 | 
				
			||||||
        'Generating your trip to ${snapshot.data}...',
 | 
					 | 
				
			||||||
        style: greeterStyle,
 | 
					        style: greeterStyle,
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    } else if (snapshot.hasError) {
 | 
					    } else if (snapshot.hasError) {
 | 
				
			||||||
      // the exact error is shown in the central part of the trip overview. No need to show it here
 | 
					      // the exact error is shown in the central part of the trip overview. No need to show it here
 | 
				
			||||||
      greeter = AutoSizeText(
 | 
					      greeter = AnimatedGradientText(
 | 
				
			||||||
        maxLines: 1,
 | 
					        text: 'Error while loading trip.',
 | 
				
			||||||
        'Error while loading trip.',
 | 
					 | 
				
			||||||
        style: greeterStyle,
 | 
					        style: greeterStyle,
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      greeter = AutoSizeText(
 | 
					      greeter = AnimatedGradientText(
 | 
				
			||||||
        maxLines: 1,
 | 
					        text: 'Creating your trip...',
 | 
				
			||||||
        'Generating your trip...',
 | 
					 | 
				
			||||||
        style: greeterStyle,
 | 
					        style: greeterStyle,
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -57,20 +101,62 @@ Widget loadingText(Trip trip) => FutureBuilder(
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AnimatedGradientText extends StatefulWidget {
 | 
				
			||||||
 | 
					  final String text;
 | 
				
			||||||
 | 
					  final TextStyle style;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const AnimatedGradientText({
 | 
				
			||||||
 | 
					    Key? key,
 | 
				
			||||||
 | 
					    required this.text,
 | 
				
			||||||
 | 
					    required this.style,
 | 
				
			||||||
 | 
					  }) : super(key: key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class _CurrentTripLoadingIndicatorState extends State<CurrentTripLoadingIndicator> {
 | 
					 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget build(BuildContext context) => Stack(
 | 
					  _AnimatedGradientTextState createState() => _AnimatedGradientTextState();
 | 
				
			||||||
    fit: StackFit.expand,
 | 
					 | 
				
			||||||
    children: [
 | 
					 | 
				
			||||||
      Center(child: loadingText(widget.trip)),
 | 
					 | 
				
			||||||
      Align(
 | 
					 | 
				
			||||||
        alignment: Alignment.bottomCenter,
 | 
					 | 
				
			||||||
        child: bottomLoadingIndicator,
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class _AnimatedGradientTextState extends State<AnimatedGradientText> with SingleTickerProviderStateMixin {
 | 
				
			||||||
 | 
					  late AnimationController _controller;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  void initState() {
 | 
				
			||||||
 | 
					    super.initState();
 | 
				
			||||||
 | 
					    _controller = AnimationController(
 | 
				
			||||||
 | 
					      duration: const Duration(seconds: 1),
 | 
				
			||||||
 | 
					      vsync: this,
 | 
				
			||||||
 | 
					    )..repeat();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  void dispose() {
 | 
				
			||||||
 | 
					    _controller.dispose();
 | 
				
			||||||
 | 
					    super.dispose();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
 | 
					    return AnimatedBuilder(
 | 
				
			||||||
 | 
					      animation: _controller,
 | 
				
			||||||
 | 
					      builder: (context, child) {
 | 
				
			||||||
 | 
					        return ShaderMask(
 | 
				
			||||||
 | 
					          shaderCallback: (bounds) {
 | 
				
			||||||
 | 
					            return LinearGradient(
 | 
				
			||||||
 | 
					              colors: [GRADIENT_START, GRADIENT_END, GRADIENT_START],
 | 
				
			||||||
 | 
					              stops: [
 | 
				
			||||||
 | 
					                _controller.value - 1.0,
 | 
				
			||||||
 | 
					                _controller.value,
 | 
				
			||||||
 | 
					                _controller.value + 1.0,
 | 
				
			||||||
 | 
					              ],
 | 
				
			||||||
 | 
					              tileMode: TileMode.mirror,
 | 
				
			||||||
 | 
					            ).createShader(bounds);
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          child: Text(
 | 
				
			||||||
 | 
					            widget.text,
 | 
				
			||||||
 | 
					            style: widget.style,
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,7 +11,7 @@ final Shader textGradient = APP_GRADIENT.createShader(Rect.fromLTWH(0.0, 0.0, 20
 | 
				
			|||||||
TextStyle greeterStyle = TextStyle(
 | 
					TextStyle greeterStyle = TextStyle(
 | 
				
			||||||
  foreground: Paint()..shader = textGradient,
 | 
					  foreground: Paint()..shader = textGradient,
 | 
				
			||||||
  fontWeight: FontWeight.bold,
 | 
					  fontWeight: FontWeight.bold,
 | 
				
			||||||
  fontSize: 26
 | 
					  fontSize: 25
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -125,7 +125,7 @@ class LandmarkType {
 | 
				
			|||||||
  LandmarkType({required this.name, this.icon = const Icon(Icons.location_on)}) {
 | 
					  LandmarkType({required this.name, this.icon = const Icon(Icons.location_on)}) {
 | 
				
			||||||
    switch (name) {
 | 
					    switch (name) {
 | 
				
			||||||
      case 'sightseeing':
 | 
					      case 'sightseeing':
 | 
				
			||||||
        icon = const Icon(Icons.church);
 | 
					        icon = const Icon(Icons.castle);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
      case 'nature':
 | 
					      case 'nature':
 | 
				
			||||||
        icon = const Icon(Icons.eco);
 | 
					        icon = const Icon(Icons.eco);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -101,10 +101,10 @@ packages:
 | 
				
			|||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
      name: collection
 | 
					      name: collection
 | 
				
			||||||
      sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
 | 
					      sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
 | 
				
			||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "1.18.0"
 | 
					    version: "1.19.0"
 | 
				
			||||||
  crypto:
 | 
					  crypto:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
@@ -412,18 +412,18 @@ packages:
 | 
				
			|||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
      name: leak_tracker
 | 
					      name: leak_tracker
 | 
				
			||||||
      sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
 | 
					      sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06"
 | 
				
			||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "10.0.5"
 | 
					    version: "10.0.7"
 | 
				
			||||||
  leak_tracker_flutter_testing:
 | 
					  leak_tracker_flutter_testing:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
      name: leak_tracker_flutter_testing
 | 
					      name: leak_tracker_flutter_testing
 | 
				
			||||||
      sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
 | 
					      sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379"
 | 
				
			||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "3.0.5"
 | 
					    version: "3.0.8"
 | 
				
			||||||
  leak_tracker_testing:
 | 
					  leak_tracker_testing:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
@@ -708,7 +708,7 @@ packages:
 | 
				
			|||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description: flutter
 | 
					    description: flutter
 | 
				
			||||||
    source: sdk
 | 
					    source: sdk
 | 
				
			||||||
    version: "0.0.99"
 | 
					    version: "0.0.0"
 | 
				
			||||||
  sliding_up_panel:
 | 
					  sliding_up_panel:
 | 
				
			||||||
    dependency: "direct main"
 | 
					    dependency: "direct main"
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
@@ -753,10 +753,10 @@ packages:
 | 
				
			|||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
      name: stack_trace
 | 
					      name: stack_trace
 | 
				
			||||||
      sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
 | 
					      sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377"
 | 
				
			||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "1.11.1"
 | 
					    version: "1.12.0"
 | 
				
			||||||
  stream_channel:
 | 
					  stream_channel:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
@@ -777,10 +777,10 @@ packages:
 | 
				
			|||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
      name: string_scanner
 | 
					      name: string_scanner
 | 
				
			||||||
      sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
 | 
					      sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3"
 | 
				
			||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "1.2.0"
 | 
					    version: "1.3.0"
 | 
				
			||||||
  synchronized:
 | 
					  synchronized:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
@@ -801,10 +801,10 @@ packages:
 | 
				
			|||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
      name: test_api
 | 
					      name: test_api
 | 
				
			||||||
      sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
 | 
					      sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c"
 | 
				
			||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "0.7.2"
 | 
					    version: "0.7.3"
 | 
				
			||||||
  typed_data:
 | 
					  typed_data:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
@@ -921,10 +921,10 @@ packages:
 | 
				
			|||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
      name: vm_service
 | 
					      name: vm_service
 | 
				
			||||||
      sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
 | 
					      sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b
 | 
				
			||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "14.2.5"
 | 
					    version: "14.3.0"
 | 
				
			||||||
  web:
 | 
					  web:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,50 +0,0 @@
 | 
				
			|||||||
import httpx
 | 
					 | 
				
			||||||
import json
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
base_url = "https://en.wikipedia.org/w/api.php"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def best_page_match(title) -> int:
 | 
					 | 
				
			||||||
    params = {
 | 
					 | 
				
			||||||
        "action": "query",
 | 
					 | 
				
			||||||
        "format": "json",
 | 
					 | 
				
			||||||
        "list": "prefixsearch",
 | 
					 | 
				
			||||||
        "pssearch": title,
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    response = httpx.get(base_url, params=params)
 | 
					 | 
				
			||||||
    data = response.json()
 | 
					 | 
				
			||||||
    data = data.get("query", {}).get("prefixsearch", [])
 | 
					 | 
				
			||||||
    titles_and_ids = {d["title"]: d["pageid"] for d in data}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for t in titles_and_ids:
 | 
					 | 
				
			||||||
        if title.lower() == t.lower():
 | 
					 | 
				
			||||||
            print("Matched")
 | 
					 | 
				
			||||||
            return titles_and_ids[t]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def get_image_url(page_id) -> str:
 | 
					 | 
				
			||||||
    # https://en.wikipedia.org/w/api.php?action=query&titles=K%C3%B6lner%20Dom&prop=imageinfo&iiprop=url&format=json
 | 
					 | 
				
			||||||
    params = {
 | 
					 | 
				
			||||||
        "action": "query",
 | 
					 | 
				
			||||||
        "format": "json",
 | 
					 | 
				
			||||||
        "prop": "pageimages",
 | 
					 | 
				
			||||||
        "pageids": page_id,
 | 
					 | 
				
			||||||
        "pithumbsize": 500,
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    response = httpx.get(base_url, params=params)
 | 
					 | 
				
			||||||
    data = response.json()
 | 
					 | 
				
			||||||
    data = data.get("query", {}).get("pages", {})
 | 
					 | 
				
			||||||
    data = data.get(str(page_id), {})
 | 
					 | 
				
			||||||
    return data.get("thumbnail", {}).get("source")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def get_image_url_from_title(title) -> str:
 | 
					 | 
				
			||||||
    page_id = best_page_match(title)
 | 
					 | 
				
			||||||
    if page_id is None:
 | 
					 | 
				
			||||||
        return None
 | 
					 | 
				
			||||||
    return get_image_url(page_id)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
print(get_image_url_from_title("kölner dom"))
 | 
					 | 
				
			||||||
print(get_image_url_from_title("grossmünster"))
 | 
					 | 
				
			||||||
print(get_image_url_from_title("eiffel tower"))
 | 
					 | 
				
			||||||
print(get_image_url_from_title("taj mahal"))
 | 
					 | 
				
			||||||
print(get_image_url_from_title("big ben"))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Reference in New Issue
	
	Block a user