diff --git a/current_results_ui/lib/main.dart b/current_results_ui/lib/main.dart index d80f5d6..cc57e30 100644 --- a/current_results_ui/lib/main.dart +++ b/current_results_ui/lib/main.dart @@ -4,13 +4,11 @@ import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; -import 'firebase_options.dart'; -import 'src/auth_service.dart'; -import 'src/platform_specific/url_strategy_stub.dart' - if (dart.library.js_interop) 'src/platform_specific/url_strategy_web.dart'; -import 'src/routing.dart'; +import 'src/app/app.dart'; +import 'src/app/firebase_options.dart'; +import 'src/shared/platform/url_strategy_stub.dart' + if (dart.library.js_interop) 'src/shared/platform/url_strategy_web.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -25,50 +23,3 @@ Future main() async { runApp(FirebaseErrorApp(error: e.toString())); } } - -class FirebaseErrorApp extends StatelessWidget { - final String error; - const FirebaseErrorApp({super.key, required this.error}); - - @override - Widget build(BuildContext context) { - return MaterialApp( - home: Scaffold( - appBar: AppBar(title: const Text('Initialization Error')), - body: Center( - child: Padding( - padding: const EdgeInsets.all(16.0), - child: SelectionArea( - child: Text( - 'Failed to initialize Firebase. Please check your configuration and ensure you have added the necessary platform-specific setup.\n\nError: $error', - textAlign: TextAlign.center, - style: TextStyle(color: Colors.red, fontSize: 16), - ), - ), - ), - ), - ), - ); - } -} - -final _router = createRouter(); - -class CurrentResultsApp extends StatelessWidget { - const CurrentResultsApp({super.key}); - - @override - Widget build(BuildContext context) { - return ChangeNotifierProvider( - create: (_) => AuthService(), - child: MaterialApp.router( - title: 'Current Results', - theme: ThemeData( - primarySwatch: Colors.blue, - visualDensity: VisualDensity.compact, - ), - routerConfig: _router, - ), - ); - } -} diff --git a/current_results_ui/lib/src/app/app.dart b/current_results_ui/lib/src/app/app.dart new file mode 100644 index 0000000..1262b44 --- /dev/null +++ b/current_results_ui/lib/src/app/app.dart @@ -0,0 +1,56 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import 'app_router.dart'; +import 'auth_service.dart'; + +class FirebaseErrorApp extends StatelessWidget { + final String error; + const FirebaseErrorApp({super.key, required this.error}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + home: Scaffold( + appBar: AppBar(title: const Text('Initialization Error')), + body: Center( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: SelectionArea( + child: Text( + 'Failed to initialize Firebase. Please check your configuration and ensure you have added the necessary platform-specific setup.\n\nError: $error', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.red, fontSize: 16), + ), + ), + ), + ), + ), + ); + } +} + +final _router = createRouter(); + +class CurrentResultsApp extends StatelessWidget { + const CurrentResultsApp({super.key}); + + @override + Widget build(BuildContext context) { + return ChangeNotifierProvider( + create: (_) => AuthService(), + child: MaterialApp.router( + title: 'Current Results', + theme: ThemeData( + primarySwatch: Colors.blue, + visualDensity: VisualDensity.compact, + ), + routerConfig: _router, + ), + ); + } +} diff --git a/current_results_ui/lib/src/routing.dart b/current_results_ui/lib/src/app/app_router.dart similarity index 88% rename from current_results_ui/lib/src/routing.dart rename to current_results_ui/lib/src/app/app_router.dart index ca6c45f..787fc85 100644 --- a/current_results_ui/lib/src/routing.dart +++ b/current_results_ui/lib/src/app/app_router.dart @@ -6,11 +6,11 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; -import '../filter.dart'; -import '../query.dart'; -import '../src/widgets/results_view.dart'; -import '../try_results_screen.dart'; -import 'data/try_query_results.dart'; +import '../data/models/filter.dart'; +import '../features/results_overview/data/results_repository.dart'; +import '../features/try_results/data/try_results_repository.dart'; +import '../features/try_results/widgets/try_results_screen.dart'; +import '../shared/widgets/results_view.dart'; typedef QueryResultsFactory = QueryResultsBase Function(Filter filter); typedef TryQueryResultsFactory = diff --git a/current_results_ui/lib/src/auth_service.dart b/current_results_ui/lib/src/app/auth_service.dart similarity index 100% rename from current_results_ui/lib/src/auth_service.dart rename to current_results_ui/lib/src/app/auth_service.dart diff --git a/current_results_ui/lib/firebase_options.dart b/current_results_ui/lib/src/app/firebase_options.dart similarity index 100% rename from current_results_ui/lib/firebase_options.dart rename to current_results_ui/lib/src/app/firebase_options.dart diff --git a/current_results_ui/lib/model/comment.dart b/current_results_ui/lib/src/data/models/comment.dart similarity index 100% rename from current_results_ui/lib/model/comment.dart rename to current_results_ui/lib/src/data/models/comment.dart diff --git a/current_results_ui/lib/src/data/models/filter.dart b/current_results_ui/lib/src/data/models/filter.dart new file mode 100644 index 0000000..1cc2c66 --- /dev/null +++ b/current_results_ui/lib/src/data/models/filter.dart @@ -0,0 +1,22 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of a source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:collection/collection.dart'; + +class Filter { + final List terms; + Filter(String termString) : terms = _parse(termString); + + static List _parse(String termString) { + if (termString.trim() == '') return List.unmodifiable([]); + return List.unmodifiable(termString.split(',').map((s) => s.trim())); + } + + @override + bool operator ==(Object other) => + other is Filter && const ListEquality().equals(terms, other.terms); + + @override + int get hashCode => const ListEquality().hash(terms); +} diff --git a/current_results_ui/lib/model/review.dart b/current_results_ui/lib/src/data/models/review.dart similarity index 100% rename from current_results_ui/lib/model/review.dart rename to current_results_ui/lib/src/data/models/review.dart diff --git a/current_results_ui/lib/model/try_build.dart b/current_results_ui/lib/src/data/models/try_build.dart similarity index 100% rename from current_results_ui/lib/model/try_build.dart rename to current_results_ui/lib/src/data/models/try_build.dart diff --git a/current_results_ui/lib/src/services/firestore_service.dart b/current_results_ui/lib/src/data/services/firestore_service.dart similarity index 100% rename from current_results_ui/lib/src/services/firestore_service.dart rename to current_results_ui/lib/src/data/services/firestore_service.dart diff --git a/current_results_ui/lib/src/services/results_service.dart b/current_results_ui/lib/src/data/services/results_service.dart similarity index 92% rename from current_results_ui/lib/src/services/results_service.dart rename to current_results_ui/lib/src/data/services/results_service.dart index 47ae91c..be96cde 100644 --- a/current_results_ui/lib/src/services/results_service.dart +++ b/current_results_ui/lib/src/data/services/results_service.dart @@ -2,11 +2,11 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -import '../../model/comment.dart'; -import '../../model/review.dart'; -import '../../model/try_build.dart'; -import '../../query.dart'; -import '../generated/query.pb.dart'; +import '../../features/results_overview/data/results_repository.dart'; +import '../../shared/generated/query.pb.dart'; +import '../models/comment.dart'; +import '../models/review.dart'; +import '../models/try_build.dart'; import 'firestore_service.dart'; class ResultsService { diff --git a/current_results_ui/lib/query.dart b/current_results_ui/lib/src/features/results_overview/data/results_repository.dart similarity index 96% rename from current_results_ui/lib/query.dart rename to current_results_ui/lib/src/features/results_overview/data/results_repository.dart index 3d4fde5..3ede4e0 100644 --- a/current_results_ui/lib/query.dart +++ b/current_results_ui/lib/src/features/results_overview/data/results_repository.dart @@ -1,4 +1,4 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. @@ -9,9 +9,9 @@ import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; -import 'filter.dart'; -import 'results.dart'; -import 'src/generated/query.pb.dart'; +import '../../../data/models/filter.dart'; +import '../../../shared/generated/query.pb.dart'; +import '../../../shared/widgets/results_widgets.dart'; const String apiHost = 'current-results-qvyo5rktwa-uc.a.run.app'; // Current endpoints proxy is limited to 1 MB response size, diff --git a/current_results_ui/lib/filter.dart b/current_results_ui/lib/src/features/results_overview/widgets/filter_ui.dart similarity index 82% rename from current_results_ui/lib/filter.dart rename to current_results_ui/lib/src/features/results_overview/widgets/filter_ui.dart index 23aeb66..ed1fbdb 100644 --- a/current_results_ui/lib/filter.dart +++ b/current_results_ui/lib/src/features/results_overview/widgets/filter_ui.dart @@ -1,30 +1,12 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; -import 'query.dart'; - -class Filter { - final List terms; - Filter(String termString) : terms = _parse(termString); - - static List _parse(String termString) { - if (termString.trim() == '') return List.unmodifiable([]); - return List.unmodifiable(termString.split(',').map((s) => s.trim())); - } - - @override - bool operator ==(Object other) => - other is Filter && const ListEquality().equals(terms, other.terms); - - @override - int get hashCode => const ListEquality().hash(terms); -} +import '../data/results_repository.dart'; class FilterUI extends StatefulWidget { const FilterUI({super.key}); diff --git a/current_results_ui/lib/instructions.dart b/current_results_ui/lib/src/features/results_overview/widgets/instructions.dart similarity index 98% rename from current_results_ui/lib/instructions.dart rename to current_results_ui/lib/src/features/results_overview/widgets/instructions.dart index 030e5e2..f94ecbe 100644 --- a/current_results_ui/lib/instructions.dart +++ b/current_results_ui/lib/src/features/results_overview/widgets/instructions.dart @@ -1,4 +1,4 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. diff --git a/current_results_ui/lib/src/data/try_query_results.dart b/current_results_ui/lib/src/features/try_results/data/try_results_repository.dart similarity index 77% rename from current_results_ui/lib/src/data/try_query_results.dart rename to current_results_ui/lib/src/features/try_results/data/try_results_repository.dart index 52cf675..2a9780f 100644 --- a/current_results_ui/lib/src/data/try_query_results.dart +++ b/current_results_ui/lib/src/features/try_results/data/try_results_repository.dart @@ -4,11 +4,11 @@ import 'dart:async'; -import '../../filter.dart'; -import '../../model/review.dart'; -import '../../query.dart'; -import '../generated/query.pb.dart'; -import '../services/results_service.dart'; +import '../../../data/models/filter.dart'; +import '../../../data/models/review.dart'; +import '../../../data/services/results_service.dart'; +import '../../../shared/generated/query.pb.dart'; +import '../../results_overview/data/results_repository.dart'; class TryQueryResults extends QueryResultsBase { final int cl; diff --git a/current_results_ui/lib/try_results_screen.dart b/current_results_ui/lib/src/features/try_results/widgets/try_results_screen.dart similarity index 92% rename from current_results_ui/lib/try_results_screen.dart rename to current_results_ui/lib/src/features/try_results/widgets/try_results_screen.dart index 4a120ae..4ec169a 100644 --- a/current_results_ui/lib/try_results_screen.dart +++ b/current_results_ui/lib/src/features/try_results/widgets/try_results_screen.dart @@ -6,9 +6,9 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart' as url_launcher; -import 'model/review.dart'; -import 'src/data/try_query_results.dart'; -import 'src/widgets/results_view.dart'; +import '../../../data/models/review.dart'; +import '../../../shared/widgets/results_view.dart'; +import '../data/try_results_repository.dart'; class TryResultsScreen extends StatefulWidget { const TryResultsScreen({super.key}); diff --git a/current_results_ui/lib/src/generated/query.pb.dart b/current_results_ui/lib/src/shared/generated/query.pb.dart similarity index 100% rename from current_results_ui/lib/src/generated/query.pb.dart rename to current_results_ui/lib/src/shared/generated/query.pb.dart diff --git a/current_results_ui/lib/src/platform_specific/url_strategy_stub.dart b/current_results_ui/lib/src/shared/platform/url_strategy_stub.dart similarity index 100% rename from current_results_ui/lib/src/platform_specific/url_strategy_stub.dart rename to current_results_ui/lib/src/shared/platform/url_strategy_stub.dart diff --git a/current_results_ui/lib/src/platform_specific/url_strategy_web.dart b/current_results_ui/lib/src/shared/platform/url_strategy_web.dart similarity index 100% rename from current_results_ui/lib/src/platform_specific/url_strategy_web.dart rename to current_results_ui/lib/src/shared/platform/url_strategy_web.dart diff --git a/current_results_ui/lib/src/widgets/app_bar_actions.dart b/current_results_ui/lib/src/shared/widgets/app_bar_actions.dart similarity index 98% rename from current_results_ui/lib/src/widgets/app_bar_actions.dart rename to current_results_ui/lib/src/shared/widgets/app_bar_actions.dart index e22a852..11cd889 100644 --- a/current_results_ui/lib/src/widgets/app_bar_actions.dart +++ b/current_results_ui/lib/src/shared/widgets/app_bar_actions.dart @@ -6,7 +6,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart' as url_launcher; -import '../auth_service.dart'; +import '../../app/auth_service.dart'; List buildAppBarActions(BuildContext context) { return [ diff --git a/current_results_ui/lib/src/widgets/results_view.dart b/current_results_ui/lib/src/shared/widgets/results_view.dart similarity index 95% rename from current_results_ui/lib/src/widgets/results_view.dart rename to current_results_ui/lib/src/shared/widgets/results_view.dart index b2cdfb1..c0a799b 100644 --- a/current_results_ui/lib/src/widgets/results_view.dart +++ b/current_results_ui/lib/src/shared/widgets/results_view.dart @@ -6,10 +6,11 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; -import '../../filter.dart'; -import '../../query.dart'; -import '../../results.dart'; +import '../../data/models/filter.dart'; +import '../../features/results_overview/data/results_repository.dart'; +import '../../features/results_overview/widgets/filter_ui.dart'; import 'app_bar_actions.dart'; +import 'results_widgets.dart'; typedef TitleBuilder = Widget Function(BuildContext context, String title); diff --git a/current_results_ui/lib/results.dart b/current_results_ui/lib/src/shared/widgets/results_widgets.dart similarity index 98% rename from current_results_ui/lib/results.dart rename to current_results_ui/lib/src/shared/widgets/results_widgets.dart index ed6250e..61e172b 100644 --- a/current_results_ui/lib/results.dart +++ b/current_results_ui/lib/src/shared/widgets/results_widgets.dart @@ -1,4 +1,4 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. @@ -8,9 +8,9 @@ import 'package:intl/intl.dart' as intl; import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart' as url_launcher; -import 'instructions.dart'; -import 'query.dart'; -import 'src/generated/query.pb.dart'; +import '../../features/results_overview/data/results_repository.dart'; +import '../../features/results_overview/widgets/instructions.dart'; +import '../generated/query.pb.dart'; const Color _lightCoral = Color.fromARGB(255, 240, 128, 128); const Color _gold = Color.fromARGB(255, 255, 215, 0); diff --git a/current_results_ui/test/auth_service_test.dart b/current_results_ui/test/auth_service_test.dart index e92cf6f..d7149fe 100644 --- a/current_results_ui/test/auth_service_test.dart +++ b/current_results_ui/test/auth_service_test.dart @@ -5,7 +5,7 @@ import 'dart:async'; import 'package:firebase_auth/firebase_auth.dart'; -import 'package:flutter_current_results/src/auth_service.dart'; +import 'package:flutter_current_results/src/app/auth_service.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; diff --git a/current_results_ui/test/query_test.dart b/current_results_ui/test/query_test.dart index 3612aa7..0c62430 100644 --- a/current_results_ui/test/query_test.dart +++ b/current_results_ui/test/query_test.dart @@ -4,10 +4,10 @@ import 'dart:convert'; -import 'package:flutter_current_results/filter.dart'; -import 'package:flutter_current_results/query.dart'; -import 'package:flutter_current_results/results.dart'; -import 'package:flutter_current_results/src/generated/query.pb.dart'; +import 'package:flutter_current_results/src/data/models/filter.dart'; +import 'package:flutter_current_results/src/features/results_overview/data/results_repository.dart'; +import 'package:flutter_current_results/src/shared/generated/query.pb.dart'; +import 'package:flutter_current_results/src/shared/widgets/results_widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:http/http.dart' as http; import 'package:mockito/annotations.dart'; diff --git a/current_results_ui/test/routing_test.dart b/current_results_ui/test/routing_test.dart index 2a441ca..40cad01 100644 --- a/current_results_ui/test/routing_test.dart +++ b/current_results_ui/test/routing_test.dart @@ -5,15 +5,15 @@ import 'dart:async'; import 'package:flutter/material.dart'; -import 'package:flutter_current_results/instructions.dart'; -import 'package:flutter_current_results/model/review.dart'; -import 'package:flutter_current_results/query.dart'; -import 'package:flutter_current_results/src/auth_service.dart'; -import 'package:flutter_current_results/src/data/try_query_results.dart'; -import 'package:flutter_current_results/src/generated/query.pb.dart'; -import 'package:flutter_current_results/src/routing.dart'; -import 'package:flutter_current_results/src/services/results_service.dart'; -import 'package:flutter_current_results/src/widgets/results_view.dart'; +import 'package:flutter_current_results/src/app/app_router.dart'; +import 'package:flutter_current_results/src/app/auth_service.dart'; +import 'package:flutter_current_results/src/data/models/review.dart'; +import 'package:flutter_current_results/src/data/services/results_service.dart'; +import 'package:flutter_current_results/src/features/results_overview/data/results_repository.dart'; +import 'package:flutter_current_results/src/features/results_overview/widgets/instructions.dart'; +import 'package:flutter_current_results/src/features/try_results/data/try_results_repository.dart'; +import 'package:flutter_current_results/src/shared/generated/query.pb.dart'; +import 'package:flutter_current_results/src/shared/widgets/results_view.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:go_router/go_router.dart'; import 'package:http/http.dart' as http; diff --git a/current_results_ui/test/try_query_results_test.dart b/current_results_ui/test/try_query_results_test.dart index cc0e685..ee4dc9c 100644 --- a/current_results_ui/test/try_query_results_test.dart +++ b/current_results_ui/test/try_query_results_test.dart @@ -2,11 +2,11 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -import 'package:flutter_current_results/filter.dart'; -import 'package:flutter_current_results/query.dart'; -import 'package:flutter_current_results/src/data/try_query_results.dart'; -import 'package:flutter_current_results/src/generated/query.pb.dart'; -import 'package:flutter_current_results/src/services/results_service.dart'; +import 'package:flutter_current_results/src/data/models/filter.dart'; +import 'package:flutter_current_results/src/data/services/results_service.dart'; +import 'package:flutter_current_results/src/features/results_overview/data/results_repository.dart'; +import 'package:flutter_current_results/src/features/try_results/data/try_results_repository.dart'; +import 'package:flutter_current_results/src/shared/generated/query.pb.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; diff --git a/current_results_ui/test/widget_test.dart b/current_results_ui/test/widget_test.dart index 0b7b5e7..448bc80 100644 --- a/current_results_ui/test/widget_test.dart +++ b/current_results_ui/test/widget_test.dart @@ -3,13 +3,13 @@ // BSD-style license that can be found in the LICENSE file. import 'package:flutter/material.dart'; -import 'package:flutter_current_results/model/review.dart'; -import 'package:flutter_current_results/query.dart'; -import 'package:flutter_current_results/src/auth_service.dart'; -import 'package:flutter_current_results/src/data/try_query_results.dart'; -import 'package:flutter_current_results/src/generated/query.pb.dart'; -import 'package:flutter_current_results/src/routing.dart'; -import 'package:flutter_current_results/try_results_screen.dart'; +import 'package:flutter_current_results/src/app/app_router.dart'; +import 'package:flutter_current_results/src/app/auth_service.dart'; +import 'package:flutter_current_results/src/data/models/review.dart'; +import 'package:flutter_current_results/src/features/results_overview/data/results_repository.dart'; +import 'package:flutter_current_results/src/features/try_results/data/try_results_repository.dart'; +import 'package:flutter_current_results/src/features/try_results/widgets/try_results_screen.dart'; +import 'package:flutter_current_results/src/shared/generated/query.pb.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:go_router/go_router.dart'; import 'package:mockito/mockito.dart';