MVVM with Provider
parent
6425f34f4f
commit
30db638877
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Flutter",
|
||||
"request": "launch",
|
||||
"type": "dart"
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 7.5 KiB |
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"main.emptyList.title": "List is empty",
|
||||
"main.emptyList.firstPaymentNotAdded": "Need add first payment"
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"main.emptyList.title": "Список пуст",
|
||||
"main.emptyList.firstPaymentNotAdded": "Необходимо добавить первый платеж",
|
||||
"edit.period": "Периодичность платежей",
|
||||
"edit.year": "Ежегодный",
|
||||
"edit.quarter": "Ежеквартальный",
|
||||
"edit.month": "Ежемесячный",
|
||||
"edit.week": "Еженедельный",
|
||||
"edit.periodCount": "Всего периодов",
|
||||
"edit.perPeriodSum": "Сумма платежа за период",
|
||||
"edit.firstPayDate": "Дата первого платежа",
|
||||
"edit.weekendWork": "Учитывать выходные дни недели",
|
||||
"edit.saturdayWork": "Суббота рабочий день",
|
||||
"edit.name": "Наименование кредита",
|
||||
"edit.nameBank": "Наименование банка",
|
||||
"edit.descriptionLabel": "Дополнительная информация",
|
||||
"edit.calendar": "Календарь",
|
||||
"edit.calendarDesc": "Календарь платежей",
|
||||
"edit.description": "Описание",
|
||||
"edit.descriptionSubtitle": "Дополнительная информация"
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
class AppRoutes {
|
||||
static const home = "/";
|
||||
static const addGame = "/addGame";
|
||||
static const history = "/history";
|
||||
static const money = "/money";
|
||||
static const profile = "/profile";
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
import 'package:equatable/equatable.dart';
|
||||
|
||||
abstract class BaseModel implements Equatable {
|
||||
Map<String, Object> toMap();
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
import 'package:logger/logger.dart';
|
||||
|
||||
import '../logger.dart';
|
||||
|
||||
class BaseService {
|
||||
Logger log;
|
||||
|
||||
BaseService({String title}) {
|
||||
this.log = getLogger(
|
||||
title ?? this.runtimeType.toString(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:logger/logger.dart';
|
||||
import '../logger.dart';
|
||||
|
||||
class BaseViewModel extends ChangeNotifier {
|
||||
String _title;
|
||||
bool _busy;
|
||||
Logger log;
|
||||
bool _isDisposed = false;
|
||||
|
||||
BaseViewModel({
|
||||
bool busy = false,
|
||||
String title,
|
||||
}) : _busy = busy,
|
||||
_title = title {
|
||||
log = getLogger(title ?? this.runtimeType.toString());
|
||||
}
|
||||
|
||||
bool get busy => this._busy;
|
||||
bool get isDisposed => this._isDisposed;
|
||||
String get title => _title ?? this.runtimeType.toString();
|
||||
|
||||
set busy(bool busy) {
|
||||
log.i(
|
||||
'busy: '
|
||||
'$title is entering '
|
||||
'${busy ? 'busy' : 'free'} state',
|
||||
);
|
||||
this._busy = busy;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
@override
|
||||
void notifyListeners() {
|
||||
if (!isDisposed) {
|
||||
super.notifyListeners();
|
||||
} else {
|
||||
log.w('notifyListeners: Notify listeners called after '
|
||||
'${title ?? this.runtimeType.toString()} has been disposed');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
log.i('dispose');
|
||||
_isDisposed = true;
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import '../core/services/ApiService.dart';
|
||||
|
||||
import '../core/logger.dart';
|
||||
import '../core/services/navigator_service.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:logger/logger.dart';
|
||||
|
||||
GetIt locator = GetIt.instance;
|
||||
|
||||
class LocatorInjector {
|
||||
static Logger _log = getLogger('LocatorInjector');
|
||||
|
||||
static Future<void> setupLocator() async {
|
||||
_log.d('Initializing Navigator Service');
|
||||
locator.registerLazySingleton(() => NavigatorService());
|
||||
_log.d('Initializing Api Service');
|
||||
locator.registerLazySingleton(() => ApiService());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
import 'dart:developer' as prefix0;
|
||||
import 'package:logger/logger.dart';
|
||||
|
||||
class SimpleLogPrinter extends LogPrinter {
|
||||
static int counter = 0;
|
||||
final String className;
|
||||
|
||||
SimpleLogPrinter(this.className);
|
||||
|
||||
@override
|
||||
List<String> log(LogEvent event) {
|
||||
prefix0.log(
|
||||
event.message,
|
||||
time: DateTime.now(),
|
||||
level: () {
|
||||
switch (event.level) {
|
||||
case Level.verbose:
|
||||
return 0;
|
||||
case Level.debug:
|
||||
return 500;
|
||||
case Level.info:
|
||||
return 0;
|
||||
case Level.warning:
|
||||
return 1500;
|
||||
case Level.error:
|
||||
return 2000;
|
||||
case Level.wtf:
|
||||
return 2000;
|
||||
default:
|
||||
return 2000;
|
||||
}
|
||||
}(),
|
||||
name: className,
|
||||
error: event.error,
|
||||
sequenceNumber: counter += 1,
|
||||
);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
Logger getLogger(String className) {
|
||||
return Logger(printer: SimpleLogPrinter(className));
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
class User {
|
||||
final String id;
|
||||
final String fullName;
|
||||
final String email;
|
||||
final String userRole;
|
||||
|
||||
User({this.id, this.fullName, this.email, this.userRole});
|
||||
|
||||
User.fromData(Map<String, dynamic> data)
|
||||
: id = data['id'],
|
||||
fullName = data['fullName'],
|
||||
email = data['email'],
|
||||
userRole = data['userRole'];
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'id': id,
|
||||
'fullName': fullName,
|
||||
'email': email,
|
||||
'userRole': userRole,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
import 'package:provider/single_child_widget.dart';
|
||||
|
||||
import '../core/locator.dart';
|
||||
import '../core/services/navigator_service.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import 'services/ApiService.dart';
|
||||
import 'services/authentication_service.dart';
|
||||
|
||||
class ProviderInjector {
|
||||
static List<SingleChildWidget> providers = [
|
||||
..._independentServices,
|
||||
..._dependentServices,
|
||||
..._consumableServices,
|
||||
];
|
||||
|
||||
static List<SingleChildWidget> _independentServices = [
|
||||
Provider.value(value: locator<NavigatorService>()),
|
||||
Provider.value(value: locator<ApiService>()),
|
||||
];
|
||||
|
||||
static List<SingleChildWidget> _dependentServices = [
|
||||
ProxyProvider<ApiService, AuthenticationService>(
|
||||
update: (context, api, authenticationService) =>
|
||||
AuthenticationService(api: api),
|
||||
)
|
||||
];
|
||||
|
||||
static List<SingleChildWidget> _consumableServices = [];
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
const String LoginViewRoute = "LoginView";
|
||||
const String HomeViewRoute = "HomeView";
|
||||
// Generate the views here
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
import './route_names.dart';
|
||||
import 'package:aman_kassa_flutter/views/home/home_view.dart';
|
||||
import 'package:aman_kassa_flutter/views/login/login_view.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
Route<dynamic> generateRoute(RouteSettings settings) {
|
||||
switch (settings.name) {
|
||||
case LoginViewRoute:
|
||||
return _getPageRoute(
|
||||
routeName: settings.name,
|
||||
viewToShow: LoginView(),
|
||||
);
|
||||
case HomeViewRoute:
|
||||
return _getPageRoute(
|
||||
routeName: settings.name,
|
||||
viewToShow: HomeView(),
|
||||
);
|
||||
// case AddAndEditViewRoute:
|
||||
// var documentToEdit = settings.arguments as Document;
|
||||
// return SlideRightRoute(widget:AddAndEditView(
|
||||
// edittingDocument: documentToEdit,
|
||||
// ));
|
||||
default:
|
||||
return MaterialPageRoute(
|
||||
builder: (_) => Scaffold(
|
||||
body: Center(
|
||||
child: Text('No route defined for ${settings.name}')),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
PageRoute _getPageRoute({String routeName, Widget viewToShow}) {
|
||||
return MaterialPageRoute(
|
||||
settings: RouteSettings(
|
||||
name: routeName,
|
||||
),
|
||||
builder: (_) => viewToShow);
|
||||
}
|
||||
|
||||
class SlideRightRoute extends PageRouteBuilder {
|
||||
final Widget widget;
|
||||
SlideRightRoute({this.widget})
|
||||
: super(
|
||||
pageBuilder: (BuildContext context, Animation<double> animation,
|
||||
Animation<double> secondaryAnimation) {
|
||||
return widget;
|
||||
},
|
||||
transitionsBuilder: (BuildContext context,
|
||||
Animation<double> animation,
|
||||
Animation<double> secondaryAnimation,
|
||||
Widget child) {
|
||||
return new SlideTransition(
|
||||
position: new Tween<Offset>(
|
||||
begin: const Offset(1.0, 0.0),
|
||||
end: Offset.zero,
|
||||
).animate(animation),
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:aman_kassa_flutter/core/base/base_service.dart';
|
||||
import 'package:aman_kassa_flutter/core/models/user.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
/// The service responsible for networking requests
|
||||
class ApiService extends BaseService {
|
||||
static const endpoint = 'https://jsonplaceholder.typicode.com';
|
||||
|
||||
var client = new http.Client();
|
||||
|
||||
Future<User> getUserProfile(int userId) async {
|
||||
// Get user profile for id
|
||||
var response = await client.get('$endpoint/users/$userId');
|
||||
|
||||
// Convert and return
|
||||
return User.fromData(json.decode(response.body));
|
||||
}
|
||||
|
||||
// Future<List<Post>> getPostsForUser(int userId) async {
|
||||
// var posts = List<Post>();
|
||||
// // Get user posts for id
|
||||
// var response = await client.get('$endpoint/posts?userId=$userId');
|
||||
|
||||
// // parse into List
|
||||
// var parsed = json.decode(response.body) as List<dynamic>;
|
||||
|
||||
// // loop and convert each item to Post
|
||||
// for (var post in parsed) {
|
||||
// posts.add(Post.fromJson(post));
|
||||
// }
|
||||
|
||||
// return posts;
|
||||
// }
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
|
||||
import 'package:aman_kassa_flutter/core/base/base_service.dart';
|
||||
import 'package:aman_kassa_flutter/core/models/user.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import 'ApiService.dart';
|
||||
|
||||
class AuthenticationService extends BaseService {
|
||||
|
||||
final ApiService _api;
|
||||
|
||||
AuthenticationService({ApiService api}) : _api = api;
|
||||
|
||||
User _currentUser;
|
||||
User get currentUser => _currentUser;
|
||||
|
||||
Future loginWithEmail({
|
||||
@required String email,
|
||||
@required String password,
|
||||
}) async {
|
||||
try {
|
||||
User result = await _api.getUserProfile(123);
|
||||
_currentUser = result;
|
||||
return result != null;
|
||||
} catch (e) {
|
||||
return e.message;
|
||||
}
|
||||
}
|
||||
|
||||
// Future<bool> isUserLoggedIn() async {
|
||||
// var user = await _firebaseAuth.currentUser();
|
||||
// await _populateCurrentUser(user);
|
||||
// return user != null;
|
||||
// }
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
import '../../core/base/base_service.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class NavigatorService extends BaseService {
|
||||
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
|
||||
|
||||
Future<T> navigateToPage<T>(MaterialPageRoute<T> pageRoute) async {
|
||||
log.i('navigateToPage: pageRoute: ${pageRoute.settings.name}');
|
||||
if (navigatorKey.currentState == null) {
|
||||
log.e('navigateToPage: Navigator State is null');
|
||||
return null;
|
||||
}
|
||||
return navigatorKey.currentState.push(pageRoute);
|
||||
}
|
||||
|
||||
Future<T> navigateToPageWithReplacement<T>(
|
||||
MaterialPageRoute<T> pageRoute) async {
|
||||
log.i('navigateToPageWithReplacement: '
|
||||
'pageRoute: ${pageRoute.settings.name}');
|
||||
if (navigatorKey.currentState == null) {
|
||||
log.e('navigateToPageWithReplacement: Navigator State is null');
|
||||
return null;
|
||||
}
|
||||
return navigatorKey.currentState.pushReplacement(pageRoute);
|
||||
}
|
||||
|
||||
void pop<T>([T result]) {
|
||||
log.i('goBack:');
|
||||
if (navigatorKey.currentState == null) {
|
||||
log.e('goBack: Navigator State is null');
|
||||
return;
|
||||
}
|
||||
navigatorKey.currentState.pop(result);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class AvatarsStack extends StatelessWidget {
|
||||
final List<String> names;
|
||||
|
||||
AvatarsStack(this.names);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final avatars = List<Widget>();
|
||||
final max = names.length - 1 > 8 ? 8 : names.length - 1;
|
||||
for (num i = max; i >= 0; i--) {
|
||||
avatars.add(Positioned(
|
||||
right: (5.0 + (25 - i) * i),
|
||||
child: CircleAvatar(
|
||||
backgroundColor: (i % 2 == 0 ? Colors.yellow : Colors.grey),
|
||||
radius: 20,
|
||||
child: Text(names[i].substring(0, 1),
|
||||
style: TextStyle(fontSize: 30)),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
return Container(
|
||||
height: 40,
|
||||
child: Stack(
|
||||
children: avatars,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:aman_kassa_flutter/features/home/avatars_stack.dart';
|
||||
import 'package:aman_kassa_flutter/model/Game.dart';
|
||||
|
||||
class GameListItem extends StatelessWidget {
|
||||
final Game game;
|
||||
|
||||
const GameListItem(this.game, {Key key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.all(5.0),
|
||||
child: Center(
|
||||
child: Card(
|
||||
child: IntrinsicHeight(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: EdgeInsets.all(10.0),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade900,
|
||||
borderRadius: BorderRadius.horizontal(
|
||||
left: Radius.circular(4.0),
|
||||
right: Radius.elliptical(15.0, 25.0))),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8.0),
|
||||
child: Text(
|
||||
'DateFormat',
|
||||
style: TextStyle(color: Colors.white, fontSize: 20),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'DateToday',
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'${game.where}',
|
||||
style: TextStyle(fontSize: 20),
|
||||
),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Text('aaa')
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: AvatarsStack(
|
||||
game.players.map((player) => player.name).toList())),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:aman_kassa_flutter/features/home/game_list_item.dart';
|
||||
import 'package:aman_kassa_flutter/features/menu/main_menu.dart';
|
||||
//import 'package:aman_kassa_flutter/testdata/test_data.dart';
|
||||
|
||||
class HomePage extends StatefulWidget {
|
||||
HomePage({Key key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_HomePageState createState() => _HomePageState();
|
||||
}
|
||||
|
||||
class _HomePageState extends State<HomePage> {
|
||||
List<GameListItem> _games;
|
||||
|
||||
_HomePageState() {
|
||||
//var games = [TestData.getRandomGames(5);
|
||||
// games.sort((a, b) => a.date.compareTo(b.date));
|
||||
// _games = games.map((game) => GameListItem(game))
|
||||
// .toList()];
|
||||
_games=[];
|
||||
}
|
||||
|
||||
Widget _getBody() => ListView.builder(
|
||||
itemBuilder: (BuildContext context, int index) => _games[index],
|
||||
itemCount: _games.length,
|
||||
);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MainMenu(_getBody());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_redux/flutter_redux.dart';
|
||||
import 'package:redux/redux.dart';
|
||||
import 'package:aman_kassa_flutter/app_routes.dart';
|
||||
import 'package:aman_kassa_flutter/redux/actions.dart';
|
||||
import 'package:aman_kassa_flutter/redux/app_state.dart';
|
||||
import 'package:aman_kassa_flutter/redux/selectors.dart';
|
||||
|
||||
class BottomNavBar extends StatelessWidget {
|
||||
Widget _addPadding(Widget child) => Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
child: child,
|
||||
);
|
||||
|
||||
Widget _getMenuItem(BuildContext context,
|
||||
{Icon icon, String routeName, @required _ViewModel vm}) {
|
||||
if (!vm.route.contains(routeName))
|
||||
return _addPadding(
|
||||
IconButton(icon: icon, onPressed: () => vm.navigate(routeName)));
|
||||
else
|
||||
return _addPadding(IconButton(
|
||||
icon: icon,
|
||||
onPressed: () => vm.navigate(routeName),
|
||||
color: Theme.of(context).accentColor.withOpacity(0.7)));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BottomAppBar(
|
||||
notchMargin: 8,
|
||||
color: Theme.of(context).primaryColor,
|
||||
shape: CircularNotchedRectangle(),
|
||||
child: StoreConnector<AppState, _ViewModel>(
|
||||
distinct: true,
|
||||
converter: (store) => _ViewModel.fromStore(store),
|
||||
builder: (context, vm) => Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: <Widget>[
|
||||
_getMenuItem(context,
|
||||
icon: Icon(Icons.home), routeName: AppRoutes.home, vm: vm),
|
||||
_getMenuItem(context,
|
||||
icon: Icon(Icons.history),
|
||||
routeName: AppRoutes.history,
|
||||
vm: vm),
|
||||
SizedBox(width: 16),
|
||||
_getMenuItem(context,
|
||||
icon: Icon(Icons.monetization_on),
|
||||
routeName: AppRoutes.money,
|
||||
vm: vm),
|
||||
_getMenuItem(context,
|
||||
icon: Icon(Icons.supervised_user_circle),
|
||||
routeName: AppRoutes.profile,
|
||||
vm: vm),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ViewModel {
|
||||
final List<String> route;
|
||||
final Function(String) navigate;
|
||||
|
||||
_ViewModel({@required this.route, @required this.navigate});
|
||||
|
||||
static _ViewModel fromStore(Store<AppState> store) {
|
||||
return _ViewModel(
|
||||
route: currentRoute(store.state),
|
||||
navigate: (routeName) =>
|
||||
store.dispatch(NavigateReplaceAction(routeName)));
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is _ViewModel &&
|
||||
runtimeType == other.runtimeType &&
|
||||
route == other.route;
|
||||
|
||||
@override
|
||||
int get hashCode => route.hashCode;
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_redux/flutter_redux.dart';
|
||||
import 'package:aman_kassa_flutter/app_routes.dart';
|
||||
import 'package:aman_kassa_flutter/features/menu/bottom_nav_bar.dart';
|
||||
import 'package:aman_kassa_flutter/redux/actions.dart';
|
||||
import 'package:aman_kassa_flutter/redux/app_state.dart';
|
||||
|
||||
class MainMenu extends StatelessWidget {
|
||||
final Widget body;
|
||||
|
||||
MainMenu(this.body);
|
||||
|
||||
Widget _getInfoBarWorkaround() =>
|
||||
PreferredSize(child: Container(), preferredSize: Size(0.0, 0.0));
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: _getInfoBarWorkaround(),
|
||||
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
|
||||
bottomNavigationBar: BottomNavBar(),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: () => StoreProvider.of<AppState>(context)
|
||||
.dispatch(NavigatePushAction(AppRoutes.addGame)),
|
||||
tooltip: 'Add new game',
|
||||
child: Icon(Icons.add),
|
||||
),
|
||||
body: body,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class NewGame extends StatelessWidget {
|
||||
Widget _getBody(BuildContext context) => Center(
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text('New Game', style: TextStyle(fontSize: 20, color: Colors.white),),
|
||||
),
|
||||
RaisedButton(
|
||||
child: Text('Show Alert'),
|
||||
onPressed: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog(
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(20.0))),
|
||||
title: Text('Alert Title'),
|
||||
content: Text('Content of alert.')));
|
||||
})
|
||||
],
|
||||
),
|
||||
));
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text('Add Game')),
|
||||
body: _getBody(context),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:aman_kassa_flutter/features/menu/main_menu.dart';
|
||||
|
||||
class StubScreen extends StatelessWidget {
|
||||
|
||||
Widget _getBody() => Center(
|
||||
child: Text('Stub Screen'),
|
||||
);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MainMenu(_getBody());
|
||||
}
|
||||
|
||||
}
|
||||
108
lib/main.dart
108
lib/main.dart
|
|
@ -1,98 +1,28 @@
|
|||
import 'package:aman_kassa_flutter/views/login/login_view.dart';
|
||||
|
||||
import 'core/locator.dart';
|
||||
import 'core/providers.dart';
|
||||
import 'core/router.dart';
|
||||
import 'core/services/navigator_service.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_redux/flutter_redux.dart';
|
||||
import 'package:redux/redux.dart';
|
||||
import 'package:aman_kassa_flutter/app_routes.dart';
|
||||
import 'package:aman_kassa_flutter/features/home/home_page.dart';
|
||||
import 'package:aman_kassa_flutter/features/newgame/new_game.dart';
|
||||
import 'package:aman_kassa_flutter/features/stub_screen.dart';
|
||||
import 'package:aman_kassa_flutter/redux/app_state.dart';
|
||||
import 'package:aman_kassa_flutter/redux/navigation_middleware.dart';
|
||||
import 'package:aman_kassa_flutter/redux/reducers/app_reducer.dart';
|
||||
import 'package:aman_kassa_flutter/route_aware_widget.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'views/home/home_view.dart';
|
||||
|
||||
void main() => runApp(MyApp());
|
||||
|
||||
final GlobalKey<NavigatorState> navigatorKey = new GlobalKey<NavigatorState>();
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
final store = Store<AppState>(appReducer,
|
||||
initialState: AppState.loading(),
|
||||
middleware: createNavigationMiddleware());
|
||||
|
||||
final theme = ThemeData(
|
||||
primaryColor: Colors.grey.shade900,
|
||||
//primaryColorLight: Colors.grey.shade800,
|
||||
//primaryColorDark: Colors.black,
|
||||
//scaffoldBackgroundColor: Colors.grey.shade800,
|
||||
// textTheme: TextTheme(
|
||||
// body1: TextStyle(color: Colors.white),
|
||||
// display1: TextStyle(color: Colors.white),
|
||||
// title: TextStyle(color: Colors.white),
|
||||
// ),
|
||||
//iconTheme: IconThemeData(color: Colors.white),
|
||||
//accentColor: Colors.yellow[500],
|
||||
);
|
||||
|
||||
MaterialPageRoute _getRoute(RouteSettings settings) {
|
||||
switch (settings.name) {
|
||||
case AppRoutes.home:
|
||||
return MainRoute(HomePage(), settings: settings);
|
||||
case AppRoutes.addGame:
|
||||
return FabRoute(NewGame(), settings: settings);
|
||||
default:
|
||||
return MainRoute(StubScreen(), settings: settings);
|
||||
}
|
||||
}
|
||||
void main() async {
|
||||
await LocatorInjector.setupLocator();
|
||||
runApp(MainApplication());
|
||||
}
|
||||
|
||||
class MainApplication extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return StoreProvider(
|
||||
store: store,
|
||||
return MultiProvider(
|
||||
providers: ProviderInjector.providers.toList(),
|
||||
child: MaterialApp(
|
||||
navigatorKey: navigatorKey,
|
||||
navigatorObservers: [routeObserver],
|
||||
title: 'AppLocalizations.appTitle',
|
||||
localizationsDelegates: [
|
||||
//AppLocalizationsDelegate(),
|
||||
],
|
||||
theme: theme,
|
||||
onGenerateRoute: (RouteSettings settings) => _getRoute(settings),
|
||||
navigatorKey: locator<NavigatorService>().navigatorKey,
|
||||
home: HomeView(),
|
||||
onGenerateRoute: generateRoute,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MainRoute<T> extends MaterialPageRoute<T> {
|
||||
MainRoute(Widget widget, {RouteSettings settings})
|
||||
: super(
|
||||
builder: (_) => RouteAwareWidget(child: widget),
|
||||
settings: settings);
|
||||
|
||||
@override
|
||||
Widget buildTransitions(BuildContext context, Animation<double> animation,
|
||||
Animation<double> secondaryAnimation, Widget child) {
|
||||
if (settings.isInitialRoute) return child;
|
||||
// Fades between routes. (If you don't want any animation,
|
||||
// just return child.)
|
||||
return FadeTransition(opacity: animation, child: child);
|
||||
}
|
||||
}
|
||||
|
||||
class FabRoute<T> extends MaterialPageRoute<T> {
|
||||
FabRoute(Widget widget, {RouteSettings settings})
|
||||
: super(
|
||||
builder: (_) => RouteAwareWidget(child: widget),
|
||||
settings: settings);
|
||||
|
||||
@override
|
||||
Widget buildTransitions(BuildContext context, Animation<double> animation,
|
||||
Animation<double> secondaryAnimation, Widget child) {
|
||||
if (settings.isInitialRoute) return child;
|
||||
return SlideTransition(
|
||||
position: new Tween<Offset>(
|
||||
begin: const Offset(0.0, 1.0),
|
||||
end: Offset.zero,
|
||||
).animate(animation),
|
||||
child: child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
class Court {
|
||||
final num number;
|
||||
final bool wasReserved;
|
||||
|
||||
Court({this.number, this.wasReserved});
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
import 'package:meta/meta.dart';
|
||||
import 'package:aman_kassa_flutter/model/Court.dart';
|
||||
import 'package:aman_kassa_flutter/model/Player.dart';
|
||||
|
||||
class Game {
|
||||
final String where;
|
||||
final DateTime date;
|
||||
final List<Court> courts;
|
||||
final List<Player> players;
|
||||
|
||||
Game({@required this.where, @required this.date, this.players, this.courts});
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
class Player {
|
||||
final String name;
|
||||
|
||||
Player(this.name);
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
|
||||
|
||||
import 'package:aman_kassa_flutter/model/Game.dart';
|
||||
|
||||
class AddGameAction {
|
||||
final Game game;
|
||||
|
||||
AddGameAction(this.game);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AddGameAction{game: $game}';
|
||||
}
|
||||
}
|
||||
|
||||
class NavigateReplaceAction {
|
||||
final String routeName;
|
||||
|
||||
NavigateReplaceAction(this.routeName);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'MainMenuNavigateAction{routeName: $routeName}';
|
||||
}
|
||||
}
|
||||
|
||||
class NavigatePushAction {
|
||||
final String routeName;
|
||||
|
||||
NavigatePushAction(this.routeName);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'NavigatePushAction{routeName: $routeName}';
|
||||
}
|
||||
}
|
||||
|
||||
class NavigatePopAction {
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'NavigatePopAction';
|
||||
}
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
import 'package:meta/meta.dart';
|
||||
import 'package:aman_kassa_flutter/app_routes.dart';
|
||||
import 'package:aman_kassa_flutter/model/Game.dart';
|
||||
|
||||
@immutable
|
||||
class AppState {
|
||||
final bool isLoading;
|
||||
final List<Game> games;
|
||||
final List<String> route;
|
||||
|
||||
AppState({
|
||||
this.isLoading = false,
|
||||
this.games = const [],
|
||||
this.route = const [AppRoutes.home],
|
||||
});
|
||||
|
||||
factory AppState.loading() => AppState(isLoading: true);
|
||||
|
||||
AppState copyWith({
|
||||
bool isLoading,
|
||||
List<Game> games,
|
||||
}) =>
|
||||
AppState(
|
||||
isLoading: isLoading ?? this.isLoading,
|
||||
games: games ?? this.games,
|
||||
route: route ?? this.route
|
||||
);
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
isLoading.hashCode ^ games.hashCode ^ route.hashCode;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is AppState &&
|
||||
runtimeType == other.runtimeType &&
|
||||
isLoading == other.isLoading &&
|
||||
games == other.games &&
|
||||
route == other.route;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AppState{isLoading: $isLoading, games: $games, route: $route}';
|
||||
}
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
import 'package:redux/redux.dart';
|
||||
import 'package:aman_kassa_flutter/main.dart';
|
||||
import 'package:aman_kassa_flutter/redux/actions.dart';
|
||||
import 'package:aman_kassa_flutter/redux/app_state.dart';
|
||||
|
||||
List<Middleware<AppState>> createNavigationMiddleware() {
|
||||
return [
|
||||
TypedMiddleware<AppState, NavigateReplaceAction>(_navigateReplace),
|
||||
TypedMiddleware<AppState, NavigatePushAction>(_navigate),
|
||||
];
|
||||
}
|
||||
|
||||
_navigateReplace(Store<AppState> store, action, NextDispatcher next) {
|
||||
final routeName = (action as NavigateReplaceAction).routeName;
|
||||
if (store.state.route.last != routeName) {
|
||||
navigatorKey.currentState.pushReplacementNamed(routeName);
|
||||
}
|
||||
next(action); //This need to be after name checks
|
||||
}
|
||||
|
||||
_navigate(Store<AppState> store, action, NextDispatcher next) {
|
||||
final routeName = (action as NavigatePushAction).routeName;
|
||||
if (store.state.route.last != routeName) {
|
||||
navigatorKey.currentState.pushNamed(routeName);
|
||||
}
|
||||
next(action); //This need to be after name checks
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
|
||||
|
||||
import 'package:aman_kassa_flutter/redux/app_state.dart';
|
||||
import 'package:aman_kassa_flutter/redux/reducers/games_reducer.dart';
|
||||
import 'package:aman_kassa_flutter/redux/reducers/loading_reducer.dart';
|
||||
import 'package:aman_kassa_flutter/redux/reducers/navigation_reducer.dart';
|
||||
|
||||
AppState appReducer(AppState state, action) {
|
||||
return AppState(
|
||||
isLoading: loadingReducer(state.isLoading, action),
|
||||
games: gamesReducer(state.games, action),
|
||||
route: navigationReducer(state.route, action)
|
||||
);
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
import 'package:redux/redux.dart';
|
||||
import 'package:aman_kassa_flutter/model/Game.dart';
|
||||
import 'package:aman_kassa_flutter/redux/actions.dart';
|
||||
|
||||
final gamesReducer = combineReducers<List<Game>>([
|
||||
TypedReducer<List<Game>, AddGameAction>(_addGame),
|
||||
]);
|
||||
|
||||
List<Game> _addGame(List<Game> games, AddGameAction action) {
|
||||
return List.from(games)..add(action.game);
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
import 'package:redux/redux.dart';
|
||||
|
||||
final loadingReducer = combineReducers<bool>([
|
||||
]);
|
||||
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
import 'package:redux/redux.dart';
|
||||
import 'package:aman_kassa_flutter/redux/actions.dart';
|
||||
|
||||
final navigationReducer = combineReducers<List<String>>([
|
||||
TypedReducer<List<String>, NavigateReplaceAction>(_navigateReplace),
|
||||
TypedReducer<List<String>, NavigatePushAction>(_navigatePush),
|
||||
TypedReducer<List<String>, NavigatePopAction>(_navigatePop),
|
||||
]);
|
||||
|
||||
List<String> _navigateReplace(
|
||||
List<String> route, NavigateReplaceAction action) =>
|
||||
[action.routeName];
|
||||
|
||||
List<String> _navigatePush(List<String> route, NavigatePushAction action) {
|
||||
var result = List<String>.from(route);
|
||||
result.add(action.routeName);
|
||||
return result;
|
||||
}
|
||||
|
||||
List<String> _navigatePop(List<String> route, NavigatePopAction action) {
|
||||
var result = List<String>.from(route);
|
||||
result.removeLast();
|
||||
return result;
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
|
||||
import './app_state.dart';
|
||||
|
||||
List<String> currentRoute(AppState state) => state.route;
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_redux/flutter_redux.dart';
|
||||
import 'package:aman_kassa_flutter/redux/actions.dart';
|
||||
import 'package:aman_kassa_flutter/redux/app_state.dart';
|
||||
|
||||
final RouteObserver<PageRoute> routeObserver = RouteObserver<PageRoute>();
|
||||
|
||||
class RouteAwareWidget extends StatefulWidget {
|
||||
final Widget child;
|
||||
|
||||
RouteAwareWidget({this.child});
|
||||
|
||||
State<RouteAwareWidget> createState() => RouteAwareWidgetState(child: child);
|
||||
}
|
||||
|
||||
class RouteAwareWidgetState extends State<RouteAwareWidget> with RouteAware {
|
||||
final Widget child;
|
||||
|
||||
RouteAwareWidgetState({this.child});
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
routeObserver.subscribe(this, ModalRoute.of(context));
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
routeObserver.unsubscribe(this);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void didPush() {
|
||||
// Route was pushed onto navigator and is now topmost route.
|
||||
}
|
||||
|
||||
@override
|
||||
void didPopNext() {
|
||||
// Covering route was popped off the navigator.
|
||||
StoreProvider.of<AppState>(context).dispatch(NavigatePopAction());
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Container(child: child);
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
library home_view;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
import 'home_view_model.dart';
|
||||
|
||||
class HomeView extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ViewModelBuilder<HomeViewModel>.reactive(
|
||||
viewModelBuilder: () => HomeViewModel(),
|
||||
onModelReady: (viewModel) {
|
||||
//viewModel.busy = true;
|
||||
},
|
||||
builder: (context, viewModel, child) {
|
||||
return buildWaitingLogo(context, viewModel, child);
|
||||
});
|
||||
}
|
||||
|
||||
Widget buildWaitingLogo(
|
||||
BuildContext context, HomeViewModel viewModel, Widget child) =>
|
||||
new Scaffold(
|
||||
body: Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
SizedBox(
|
||||
width: 300,
|
||||
height: 100,
|
||||
child: Image.asset('assets/images/icon_large.png'),
|
||||
),
|
||||
CircularProgressIndicator(
|
||||
strokeWidth: 3,
|
||||
valueColor: AlwaysStoppedAnimation(
|
||||
Colors.yellow[300],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
));
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import 'package:aman_kassa_flutter/core/base/base_view_model.dart';
|
||||
import 'package:aman_kassa_flutter/core/locator.dart';
|
||||
import 'package:aman_kassa_flutter/core/route_names.dart';
|
||||
import 'package:aman_kassa_flutter/core/services/navigator_service.dart';
|
||||
import 'package:aman_kassa_flutter/views/login/login_view.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class HomeViewModel extends BaseViewModel {
|
||||
final NavigatorService _navigationService = locator<NavigatorService>();
|
||||
int _counter;
|
||||
|
||||
HomeViewModel({int counter = 0}) : this._counter = counter;
|
||||
|
||||
int get counter => this._counter;
|
||||
set counter(int value) {
|
||||
this._counter = value;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void increment() => this.counter += 1;
|
||||
|
||||
void goToLogin() {
|
||||
_navigationService.navigateToPage(MaterialPageRoute(builder: (context) => LoginView()));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
library login_view;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
import 'login_view_model.dart';
|
||||
|
||||
class LoginView extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
//LoginViewModel viewModel = LoginViewModel();
|
||||
return ViewModelBuilder<LoginViewModel>.reactive(
|
||||
viewModelBuilder: () => LoginViewModel(),
|
||||
onModelReady: (viewModel) {
|
||||
// Do something once your viewModel is initialized
|
||||
},
|
||||
builder: (context, viewModel, child) {
|
||||
return Scaffold(
|
||||
body: Center(child: Text('LoginMobile')),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
import 'package:aman_kassa_flutter/core/base/base_view_model.dart';
|
||||
|
||||
class LoginViewModel extends BaseViewModel {
|
||||
LoginViewModel();
|
||||
|
||||
// Add ViewModel specific code here
|
||||
}
|
||||
110
pubspec.lock
110
pubspec.lock
|
|
@ -7,42 +7,42 @@ packages:
|
|||
name: archive
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.11"
|
||||
version: "2.0.13"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: args
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.5.2"
|
||||
version: "1.6.0"
|
||||
async:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.4.0"
|
||||
version: "2.4.1"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: boolean_selector
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.5"
|
||||
version: "2.0.0"
|
||||
charcode:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: charcode
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
version: "1.1.3"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: collection
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.14.11"
|
||||
version: "1.14.12"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -56,7 +56,7 @@ packages:
|
|||
name: crypto
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.3"
|
||||
version: "2.1.4"
|
||||
cupertino_icons:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
@ -64,30 +64,58 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.1.3"
|
||||
equatable:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: equatable
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_redux:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_redux
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.5.4"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
get_it:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: get_it
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
http:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: http
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.12.1"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http_parser
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.1.4"
|
||||
image:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
version: "2.1.12"
|
||||
logger:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: logger
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.9.1"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -102,6 +130,20 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.8"
|
||||
nested:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: nested
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.0.4"
|
||||
observable_ish:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: observable_ish
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -123,20 +165,34 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.4.0"
|
||||
provider:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: provider
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.1.2"
|
||||
provider_architecture:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: provider_architecture
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.1+1"
|
||||
quiver:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: quiver
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.5"
|
||||
redux:
|
||||
version: "2.1.3"
|
||||
responsive_builder:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: redux
|
||||
name: responsive_builder
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
version: "0.1.9"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
|
|
@ -148,7 +204,7 @@ packages:
|
|||
name: source_span
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.5.5"
|
||||
version: "1.7.0"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -156,6 +212,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.9.3"
|
||||
stacked:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: stacked
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.5.2"
|
||||
stream_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -183,7 +246,7 @@ packages:
|
|||
name: test_api
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.11"
|
||||
version: "0.2.15"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -204,6 +267,7 @@ packages:
|
|||
name: xml
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.5.0"
|
||||
version: "3.6.1"
|
||||
sdks:
|
||||
dart: ">=2.4.0 <3.0.0"
|
||||
dart: ">=2.7.0 <3.0.0"
|
||||
flutter: ">=1.16.0"
|
||||
|
|
|
|||
67
pubspec.yaml
67
pubspec.yaml
|
|
@ -1,59 +1,40 @@
|
|||
name: aman_kassa_flutter
|
||||
description: A new Flutter project.
|
||||
|
||||
# The following defines the version and build number for your application.
|
||||
# A version number is three numbers separated by dots, like 1.2.43
|
||||
# followed by an optional build number separated by a +.
|
||||
# Both the version and the builder number may be overridden in flutter
|
||||
# build by specifying --build-name and --build-number, respectively.
|
||||
# In Android, build-name is used as versionName while build-number used as versionCode.
|
||||
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
|
||||
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
||||
# Read more about iOS versioning at
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
version: 1.0.0+1
|
||||
|
||||
environment:
|
||||
sdk: ">=2.1.0 <3.0.0"
|
||||
|
||||
sdk: '>=2.3.0 <3.0.0'
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
|
||||
redux: ^3.0.0
|
||||
flutter_redux: ^0.5.0
|
||||
|
||||
# The following adds the Cupertino Icons font to your application.
|
||||
# Use with the CupertinoIcons class for iOS style icons.
|
||||
cupertino_icons: ^0.1.2
|
||||
|
||||
flutter:
|
||||
sdk: flutter
|
||||
cupertino_icons: ^0.1.2
|
||||
stacked : ^1.5.2
|
||||
provider_architecture: ^1.0.3
|
||||
responsive_builder: ^0.1.4
|
||||
provider: ^4.1.2
|
||||
logger: ^0.9.1
|
||||
get_it: ^3.0.3
|
||||
equatable: ^1.1.1
|
||||
http: ^0.12.1
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
|
||||
|
||||
# For information on the generic Dart part of this file, see the
|
||||
# following page: https://dart.dev/tools/pub/pubspec
|
||||
|
||||
# The following section is specific to Flutter.
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
flutter:
|
||||
uses-material-design: true
|
||||
|
||||
# The following line ensures that the Material Icons font is
|
||||
# included with your application, so that you can use the icons in
|
||||
# the material Icons class.
|
||||
uses-material-design: true
|
||||
|
||||
# To add assets to your application, add an assets section, like this:
|
||||
# assets:
|
||||
# - images/a_dot_burr.jpeg
|
||||
# - images/a_dot_ham.jpeg
|
||||
|
||||
assets:
|
||||
- assets/images/logo.png
|
||||
- assets/images/icon_large.png
|
||||
- assets/lang/en.json
|
||||
- assets/lang/ru.json
|
||||
|
||||
# An image asset can refer to one or more resolution-specific "variants", see
|
||||
# https://flutter.dev/assets-and-images/#resolution-aware.
|
||||
|
||||
|
||||
# For details regarding adding assets from package dependencies, see
|
||||
# https://flutter.dev/assets-and-images/#from-packages
|
||||
|
||||
|
||||
# To add custom fonts to your application, add a fonts section here,
|
||||
# in this "flutter" section. Each entry in this list should have a
|
||||
# "family" key with the font family name, and a "fonts" key with a
|
||||
|
|
@ -72,4 +53,4 @@ flutter:
|
|||
# weight: 700
|
||||
#
|
||||
# For details regarding fonts from package dependencies,
|
||||
# see https://flutter.dev/custom-fonts/#from-packages
|
||||
# see https://flutter.dev/custom-fonts/#from-packages
|
||||
|
|
@ -13,7 +13,7 @@ import 'package:aman_kassa_flutter/main.dart';
|
|||
void main() {
|
||||
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
||||
// Build our app and trigger a frame.
|
||||
await tester.pumpWidget(MyApp());
|
||||
await tester.pumpWidget(MainApplication());
|
||||
|
||||
// Verify that our counter starts at 0.
|
||||
expect(find.text('0'), findsOneWidget);
|
||||
|
|
|
|||
Loading…
Reference in New Issue