Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 12 additions & 24 deletions mobile/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -1,28 +1,16 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
include: package:very_good_analysis/analysis_options.yaml

# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
analyzer:
errors:
invalid_annotation_target: ignore
exclude:
- "**/*.g.dart"
- "**/*.freezed.dart"
- "lib/generated/**"

linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at https://dart.dev/lints.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule

# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
# App code, not a published library.
public_member_api_docs: false
# `dart format` is authoritative for line length.
lines_longer_than_80_chars: false
14 changes: 6 additions & 8 deletions mobile/integration_test/brush_smoke_test.dart
Original file line number Diff line number Diff line change
@@ -1,27 +1,25 @@
import 'package:beebeebike/api/client.dart';
import 'package:beebeebike/app.dart';
import 'package:beebeebike/providers/brush_provider.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:http_mock_adapter/http_mock_adapter.dart';
import 'package:integration_test/integration_test.dart';

import 'package:beebeebike/api/client.dart';
import 'package:beebeebike/app.dart';
import 'package:beebeebike/providers/brush_provider.dart';

void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();

testWidgets('paint FAB flips paint mode and shows PaintSheet',
(tester) async {
final dio = Dio(BaseOptions(baseUrl: 'http://test.local'));
final adapter = DioAdapter(dio: dio);
adapter
..onGet('/api/auth/me', (r) => r.reply(401, {}))
DioAdapter(dio: dio)
..onGet('/api/auth/me', (r) => r.reply(401, <String, dynamic>{}))
..onPost('/api/auth/anonymous',
(r) => r.reply(200, {'id': 'anon', 'account_type': 'anonymous'}))
..onGet('/api/ratings',
(r) => r.reply(200, {'type': 'FeatureCollection', 'features': []}));
(r) => r.reply(200, {'type': 'FeatureCollection', 'features': <dynamic>[]}));

await tester.pumpWidget(ProviderScope(
overrides: [dioProvider.overrideWithValue(dio)],
Expand Down
6 changes: 4 additions & 2 deletions mobile/integration_test/navigation_smoke_test.dart
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import 'dart:async';

import 'package:beebeebike/main.dart' as app;
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:beebeebike/main.dart' as app;

void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();

testWidgets(
'app launches and renders the map screen',
(tester) async {
app.main();
unawaited(app.main());
// MapLibre keeps frames coming, so pumpAndSettle can hang. Pump a
// bounded number of frames instead and then assert the scaffold.
for (var i = 0; i < 20; i++) {
Expand Down
15 changes: 7 additions & 8 deletions mobile/lib/api/auth_api.dart
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
import 'package:beebeebike/models/user.dart';
import 'package:dio/dio.dart';

import '../models/user.dart';

class AuthApi {
AuthApi(this._dio);

final Dio _dio;

Future<User> anonymous() async =>
User.fromJson((await _dio.post('/api/auth/anonymous')).data as Map<String, dynamic>);
User.fromJson((await _dio.post<dynamic>('/api/auth/anonymous')).data as Map<String, dynamic>);

Future<User> me() async =>
User.fromJson((await _dio.get('/api/auth/me')).data as Map<String, dynamic>);
User.fromJson((await _dio.get<dynamic>('/api/auth/me')).data as Map<String, dynamic>);

Future<User> login(String email, String password) async => User.fromJson(
(await _dio.post('/api/auth/login', data: {
(await _dio.post<dynamic>('/api/auth/login', data: <String, dynamic>{
'email': email,
'password': password,
}))
Expand All @@ -23,7 +22,7 @@ class AuthApi {

Future<User> register(String email, String password, String? displayName) async =>
User.fromJson(
(await _dio.post('/api/auth/register', data: {
(await _dio.post<dynamic>('/api/auth/register', data: <String, dynamic>{
'email': email,
'password': password,
'display_name': displayName,
Expand All @@ -32,10 +31,10 @@ class AuthApi {
);

Future<void> logout() async {
await _dio.post('/api/auth/logout');
await _dio.post<dynamic>('/api/auth/logout');
}

Future<void> deleteAccount() async {
await _dio.delete('/api/auth/account');
await _dio.delete<dynamic>('/api/auth/account');
}
}
5 changes: 2 additions & 3 deletions mobile/lib/api/client.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import 'dart:ui' as ui;

import 'package:beebeebike/app.dart';
import 'package:beebeebike/providers/locale_provider.dart';
import 'package:cookie_jar/cookie_jar.dart';
import 'package:dio/dio.dart';
import 'package:dio_cookie_manager/dio_cookie_manager.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import '../app.dart';
import '../providers/locale_provider.dart';

/// Override this in main() with getApplicationSupportDirectory().path.
final cookieStoragePathProvider = Provider<String>(
(_) => throw UnimplementedError('cookieStoragePathProvider not overridden'),
Expand Down
11 changes: 6 additions & 5 deletions mobile/lib/api/geocode_api.dart
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import 'package:beebeebike/models/geocode_result.dart';
import 'package:dio/dio.dart';

import '../models/geocode_result.dart';

class GeocodeApi {
GeocodeApi(this._dio);

final Dio _dio;

Future<List<GeocodeResult>> search(String query) async {
final response = await _dio.get('/api/geocode', queryParameters: {'q': query});
final features = (response.data['features'] as List).cast<Map<String, dynamic>>();
final response = await _dio.get<dynamic>('/api/geocode', queryParameters: <String, dynamic>{'q': query});
final data = response.data as Map<String, dynamic>;
final features = (data['features'] as List).cast<Map<String, dynamic>>();
return features.map((f) {
final props = f['properties'] as Map<String, dynamic>;
final coords = (f['geometry']?['coordinates'] as List?) ?? [0.0, 0.0];
final geometry = f['geometry'] as Map<String, dynamic>?;
final coords = (geometry?['coordinates'] as List?) ?? const <num>[0, 0];
final rawName = (props['name'] as String?) ?? '';
final street = (props['street'] as String?) ?? '';
final housenumber = (props['housenumber'] as String?) ?? '';
Expand Down
9 changes: 4 additions & 5 deletions mobile/lib/api/locations_api.dart
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import 'package:beebeebike/models/location.dart';
import 'package:dio/dio.dart';

import '../models/location.dart';

class LocationsApi {
LocationsApi(this._dio);

final Dio _dio;

Future<Location?> getHome() async {
try {
final response = await _dio.get('/api/locations/home');
final response = await _dio.get<dynamic>('/api/locations/home');
final data = response.data;
if (data == null) return null;
return Location.fromJson(Map<String, dynamic>.from(data as Map));
Expand All @@ -20,7 +19,7 @@ class LocationsApi {
}

Future<Location> setHome(Location location) async {
final response = await _dio.put('/api/locations/home', data: {
final response = await _dio.put<dynamic>('/api/locations/home', data: <String, dynamic>{
'label': location.label,
'lng': location.lng,
'lat': location.lat,
Expand All @@ -29,6 +28,6 @@ class LocationsApi {
}

Future<void> deleteHome() async {
await _dio.delete('/api/locations/home');
await _dio.delete<dynamic>('/api/locations/home');
}
}
7 changes: 3 additions & 4 deletions mobile/lib/api/ratings_api.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import 'package:beebeebike/api/client.dart';
import 'package:dio/dio.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import 'client.dart';

class RatingsApi {
RatingsApi(this._dio);

Expand All @@ -17,9 +16,9 @@ class RatingsApi {
String bbox, {
CancelToken? cancelToken,
}) async {
final response = await _dio.get(
final response = await _dio.get<dynamic>(
'/api/ratings',
queryParameters: {'bbox': bbox},
queryParameters: <String, dynamic>{'bbox': bbox},
cancelToken: cancelToken,
);
return Map<String, dynamic>.from(response.data as Map);
Expand Down
13 changes: 6 additions & 7 deletions mobile/lib/api/ratings_paint_api.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import 'package:beebeebike/api/client.dart';
import 'package:beebeebike/models/paint_response.dart';
import 'package:dio/dio.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import '../models/paint_response.dart';
import 'client.dart';

class RatingsPaintApi {
RatingsPaintApi(this._dio);

Expand All @@ -14,9 +13,9 @@ class RatingsPaintApi {
required int value,
int? targetId,
}) async {
final response = await _dio.put(
final response = await _dio.put<dynamic>(
'/api/ratings/paint',
data: {
data: <String, dynamic>{
'geometry': geometry,
'value': value,
'target_id': targetId,
Expand All @@ -28,14 +27,14 @@ class RatingsPaintApi {
}

Future<PaintResponse> undo() async {
final response = await _dio.post('/api/ratings/undo');
final response = await _dio.post<dynamic>('/api/ratings/undo');
return PaintResponse.fromJson(
Map<String, dynamic>.from(response.data as Map),
);
}

Future<PaintResponse> redo() async {
final response = await _dio.post('/api/ratings/redo');
final response = await _dio.post<dynamic>('/api/ratings/redo');
return PaintResponse.fromJson(
Map<String, dynamic>.from(response.data as Map),
);
Expand Down
7 changes: 3 additions & 4 deletions mobile/lib/api/routing_api.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import 'package:beebeebike/models/route_preview.dart';
import 'package:dio/dio.dart';

import '../models/route_preview.dart';

class RoutingApi {
RoutingApi(this._dio);

Expand All @@ -13,7 +12,7 @@ class RoutingApi {
double? ratingWeight,
double? distanceInfluence,
}) async {
final response = await _dio.post('/api/route', data: {
final response = await _dio.post<dynamic>('/api/route', data: <String, dynamic>{
'origin': origin,
'destination': destination,
if (ratingWeight != null) 'rating_weight': ratingWeight,
Expand All @@ -28,7 +27,7 @@ class RoutingApi {
double? ratingWeight,
double? distanceInfluence,
}) async {
final response = await _dio.post('/api/navigate', data: {
final response = await _dio.post<dynamic>('/api/navigate', data: <String, dynamic>{
'origin': origin,
'destination': destination,
if (ratingWeight != null) 'rating_weight': ratingWeight,
Expand Down
17 changes: 8 additions & 9 deletions mobile/lib/app.dart
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import 'package:beebeebike/config/app_config.dart';
import 'package:beebeebike/l10n/generated/app_localizations.dart';
import 'package:beebeebike/providers/auth_provider.dart';
import 'package:beebeebike/providers/locale_provider.dart';
import 'package:beebeebike/providers/onboarding_provider.dart';
import 'package:beebeebike/screens/map_screen.dart';
import 'package:beebeebike/screens/onboarding_screen.dart';
import 'package:beebeebike/theme/app_theme.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import 'config/app_config.dart';
import 'l10n/generated/app_localizations.dart';
import 'providers/auth_provider.dart';
import 'providers/locale_provider.dart';
import 'providers/onboarding_provider.dart';
import 'screens/map_screen.dart';
import 'screens/onboarding_screen.dart';
import 'theme/app_theme.dart';

final appConfigProvider = Provider<AppConfig>((ref) => AppConfig.fromEnvironment());

class BeeBeeBikeApp extends ConsumerWidget {
Expand Down
Loading
Loading