Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0cda6f9a48 |
@@ -51,7 +51,7 @@ android {
|
||||
applicationId "ru.naggadim.reverse_nn.reverse_nn"
|
||||
// You can update the following values to match your application needs.
|
||||
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
|
||||
minSdkVersion flutter.minSdkVersion
|
||||
minSdkVersion 23
|
||||
targetSdkVersion flutter.targetSdkVersion
|
||||
versionCode flutterVersionCode.toInteger()
|
||||
versionName flutterVersionName
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"rules": [
|
||||
{
|
||||
"after": "2024-08-01T00:00:00.000",
|
||||
"before": "2024-12-16T03:59:99.999",
|
||||
"before": "2024-12-16T03:59:59.999999",
|
||||
"dataset": {
|
||||
"monday": "daily-1",
|
||||
"tuesday": "daily-1",
|
||||
@@ -10,13 +10,7 @@
|
||||
"thursday": "daily-1",
|
||||
"friday": "friday-1",
|
||||
"saturday": "saturday-1",
|
||||
"sunday": "sunday-1",
|
||||
|
||||
"2024-11-01": "daily-1",
|
||||
"2024-11-02": "friday-1",
|
||||
"2024-11-03": "saturday-1",
|
||||
"2024-11-04": "sunday-1",
|
||||
"2024-11-05": "daily-1"
|
||||
"sunday": "sunday-1"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:get_storage/get_storage.dart';
|
||||
import 'package:reverse_nn/application/controllers/application_controller.dart';
|
||||
import 'package:reverse_nn/pages/home_page.dart';
|
||||
import 'package:reverse_nn/ui/screens/home_screen.dart';
|
||||
|
||||
class ReversNNApplication extends StatelessWidget {
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:reverse_nn/application/dto/schedule.dart';
|
||||
import 'package:reverse_nn/application/services/remote_config/service.dart';
|
||||
import 'package:reverse_nn/application/services/schedule.dart';
|
||||
import 'package:reverse_nn/ui/screens/calendar_screen.dart';
|
||||
|
||||
class CalendarScheduleController extends GetxController {
|
||||
Rx<DateTime> date = DateTime.now().copyWith(hour: 12, minute: 00).obs;
|
||||
RxBool loading = false.obs;
|
||||
Rx<List<Map<String, dynamic>>?> schedule = null.obs;
|
||||
Rx<List<ScheduleItem>?> schedule = null.obs;
|
||||
|
||||
@override void onReady() {
|
||||
super.onReady();
|
||||
@@ -26,14 +28,26 @@ class CalendarScheduleController extends GetxController {
|
||||
}
|
||||
|
||||
void goToPrevDay() async {
|
||||
if(date.value.isBefore(DateTime(2024, 8, 1, 23, 59))) return;
|
||||
date = (date.value.copyWith().subtract(const Duration(days: 1)).copyWith(hour: 12, minute: 0)).obs;
|
||||
final newDate = date.value
|
||||
.copyWith(hour: 12, minute: 0, second: 0, microsecond: 0, millisecond: 0)
|
||||
.subtract(const Duration(days: 1));
|
||||
final dateStart = await ReverseNNRuStoreRemoteConfig().getStartScheduleDate();
|
||||
|
||||
if(newDate.isBefore(dateStart)) return;
|
||||
|
||||
date = newDate.obs;
|
||||
loadSchedule(date.value);
|
||||
}
|
||||
|
||||
void goToNextDay() async {
|
||||
if(date.value.isAfter(DateTime(2025, 12, 31))) return;
|
||||
date = (date.value.copyWith().add(const Duration(days: 1)).copyWith(hour: 12, minute: 0)).obs;
|
||||
final newDate = date.value
|
||||
.copyWith(hour: 12, minute: 0, second: 0, microsecond: 0, millisecond: 0)
|
||||
.add(const Duration(days: 1));
|
||||
final dateEnd = await ReverseNNRuStoreRemoteConfig().getEndScheduleDate();
|
||||
|
||||
if(newDate.isAfter(dateEnd)) return;
|
||||
|
||||
date = newDate.obs;
|
||||
loadSchedule(date.value);
|
||||
}
|
||||
}
|
||||
@@ -2,10 +2,11 @@ import 'dart:developer';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:reverse_nn/application/dto/schedule.dart';
|
||||
import 'package:reverse_nn/application/services/schedule.dart';
|
||||
|
||||
class ScheduleController extends GetxController {
|
||||
Rx<Map<String, dynamic>?> currentSchedule = null.obs;
|
||||
Rx<ScheduleItem?> currentSchedule = null.obs;
|
||||
|
||||
@override void onReady() {
|
||||
super.onReady();
|
||||
|
||||
25
lib/application/dto/direction.dart
Normal file
25
lib/application/dto/direction.dart
Normal file
@@ -0,0 +1,25 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
enum Direction {
|
||||
@JsonValue('in_city') inCity,
|
||||
@JsonValue('change') change,
|
||||
@JsonValue('out_city') outCity;
|
||||
|
||||
String displayName() {
|
||||
switch(this) {
|
||||
case Direction.inCity: return 'В город';
|
||||
case Direction.change: return 'Переключение';
|
||||
case Direction.outCity: return 'Из города';
|
||||
}
|
||||
}
|
||||
|
||||
IconData icon() {
|
||||
switch(this) {
|
||||
case Direction.inCity: return Icons.input_outlined;
|
||||
case Direction.change: return Icons.change_circle_outlined;
|
||||
case Direction.outCity: return Icons.output_outlined;
|
||||
}
|
||||
}
|
||||
}
|
||||
15
lib/application/dto/rule.dart
Normal file
15
lib/application/dto/rule.dart
Normal file
@@ -0,0 +1,15 @@
|
||||
import "package:json_annotation/json_annotation.dart" show FieldRename, JsonSerializable;
|
||||
|
||||
part 'rule.g.dart';
|
||||
|
||||
@JsonSerializable(fieldRename: FieldRename.snake, explicitToJson: true)
|
||||
class Rule {
|
||||
final DateTime after;
|
||||
final DateTime? before;
|
||||
final Map<String, String> dataset;
|
||||
|
||||
Rule({required this.after, required this.before, required this.dataset});
|
||||
|
||||
factory Rule.fromJson(Map<String, dynamic> json) => _$RuleFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$RuleToJson(this);
|
||||
}
|
||||
21
lib/application/dto/rule.g.dart
Normal file
21
lib/application/dto/rule.g.dart
Normal file
@@ -0,0 +1,21 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'rule.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
Rule _$RuleFromJson(Map<String, dynamic> json) => Rule(
|
||||
after: DateTime.parse(json['after'] as String),
|
||||
before: json['before'] == null
|
||||
? null
|
||||
: DateTime.parse(json['before'] as String),
|
||||
dataset: Map<String, String>.from(json['dataset'] as Map),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$RuleToJson(Rule instance) => <String, dynamic>{
|
||||
'after': instance.after.toIso8601String(),
|
||||
'before': instance.before?.toIso8601String(),
|
||||
'dataset': instance.dataset,
|
||||
};
|
||||
41
lib/application/dto/schedule.dart
Normal file
41
lib/application/dto/schedule.dart
Normal file
@@ -0,0 +1,41 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:reverse_nn/application/dto/direction.dart';
|
||||
|
||||
part 'schedule.g.dart';
|
||||
|
||||
@JsonSerializable(fieldRename: FieldRename.snake, explicitToJson: true)
|
||||
class ScheduleItem {
|
||||
final int duration;
|
||||
final Direction direction;
|
||||
|
||||
final DateTime? start;
|
||||
final DateTime? end;
|
||||
final bool? showStartDate;
|
||||
final bool? showEndDate;
|
||||
|
||||
ScheduleItem({
|
||||
required this.duration,
|
||||
required this.direction,
|
||||
this.start,
|
||||
this.end,
|
||||
this.showStartDate,
|
||||
this.showEndDate
|
||||
});
|
||||
|
||||
factory ScheduleItem.fromJson(Map<String, dynamic> json) => _$ScheduleItemFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$ScheduleItemToJson(this);
|
||||
|
||||
ScheduleItem fillAdditional({
|
||||
required DateTime start,
|
||||
required DateTime end,
|
||||
required bool showStartDate,
|
||||
required bool showEndDate
|
||||
}) => ScheduleItem(
|
||||
duration: duration,
|
||||
direction: direction,
|
||||
start: start,
|
||||
end: end,
|
||||
showStartDate: showStartDate,
|
||||
showEndDate: showEndDate,
|
||||
);
|
||||
}
|
||||
34
lib/application/dto/schedule.g.dart
Normal file
34
lib/application/dto/schedule.g.dart
Normal file
@@ -0,0 +1,34 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'schedule.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
ScheduleItem _$ScheduleItemFromJson(Map<String, dynamic> json) => ScheduleItem(
|
||||
duration: (json['duration'] as num).toInt(),
|
||||
direction: $enumDecode(_$DirectionEnumMap, json['direction']),
|
||||
start: json['start'] == null
|
||||
? null
|
||||
: DateTime.parse(json['start'] as String),
|
||||
end: json['end'] == null ? null : DateTime.parse(json['end'] as String),
|
||||
showStartDate: json['show_start_date'] as bool?,
|
||||
showEndDate: json['show_end_date'] as bool?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$ScheduleItemToJson(ScheduleItem instance) =>
|
||||
<String, dynamic>{
|
||||
'duration': instance.duration,
|
||||
'direction': _$DirectionEnumMap[instance.direction]!,
|
||||
'start': instance.start?.toIso8601String(),
|
||||
'end': instance.end?.toIso8601String(),
|
||||
'show_start_date': instance.showStartDate,
|
||||
'show_end_date': instance.showEndDate,
|
||||
};
|
||||
|
||||
const _$DirectionEnumMap = {
|
||||
Direction.inCity: 'in_city',
|
||||
Direction.change: 'change',
|
||||
Direction.outCity: 'out_city',
|
||||
};
|
||||
5
lib/application/services/remote_config/parameters.dart
Normal file
5
lib/application/services/remote_config/parameters.dart
Normal file
@@ -0,0 +1,5 @@
|
||||
import 'package:flutter_rustore_remoteconfig/rustore_remote_config.dart';
|
||||
|
||||
class ReverseNNRemoteConfigParameters extends StaticParameters {
|
||||
|
||||
}
|
||||
131
lib/application/services/remote_config/service.dart
Normal file
131
lib/application/services/remote_config/service.dart
Normal file
@@ -0,0 +1,131 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_rustore_remoteconfig/flutter_rustore_remoteconfig.dart';
|
||||
import 'package:flutter_rustore_remoteconfig/rustore_remote_config.dart';
|
||||
import 'package:reverse_nn/application/dto/rule.dart';
|
||||
import 'package:reverse_nn/application/dto/schedule.dart';
|
||||
import 'package:reverse_nn/configuration.dart';
|
||||
import 'package:reverse_nn/application/services/remote_config/parameters.dart';
|
||||
|
||||
class ReverseNNRuStoreRemoteConfig {
|
||||
void create() {
|
||||
FlutterRustoreRemoteconfig.create(
|
||||
Configuration.ruStoreRemoteConfigAppID,
|
||||
PluginUpdateBehavior.defaultBehavior,
|
||||
15,
|
||||
ReverseNNRemoteConfigParameters(),
|
||||
onInitComplete: () {
|
||||
if(kDebugMode) { log('RuStore Remote Config - onInitComplete'); }
|
||||
},
|
||||
onFirstLoadComplete: () {
|
||||
if(kDebugMode) { log('RuStore Remote Config - onFirstLoadComplete'); }
|
||||
},
|
||||
onMemoryCacheUpdated: () {
|
||||
if(kDebugMode) { log('RuStore Remote Config - onMemoryCacheUpdated'); }
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Future<DateTime> getStartScheduleDate() async {
|
||||
try {
|
||||
FlutterRustoreRemoteconfig.init();
|
||||
final remoteConfig = await FlutterRustoreRemoteconfig.getRemoteConfig();
|
||||
final startScheduleDate = remoteConfig.getString('startScheduleDate');
|
||||
|
||||
return startScheduleDate != null
|
||||
? DateTime.parse(startScheduleDate)
|
||||
: DateTime(2024, 8, 1);
|
||||
}
|
||||
catch (error) {
|
||||
if(kDebugMode) {
|
||||
log('ReverseNNRuStoreRemoteConfig.getStartScheduleDate - error - ${error.toString()}');
|
||||
}
|
||||
return DateTime(2024, 8, 1);
|
||||
}
|
||||
}
|
||||
|
||||
Future<DateTime> getEndScheduleDate() async {
|
||||
try {
|
||||
FlutterRustoreRemoteconfig.init();
|
||||
final remoteConfig = await FlutterRustoreRemoteconfig.getRemoteConfig();
|
||||
final endScheduleDate = remoteConfig.getString('endScheduleDate');
|
||||
|
||||
return endScheduleDate != null
|
||||
? DateTime.parse(endScheduleDate)
|
||||
: DateTime(2025, 12, 31, 23, 59, 59, 999, 999);
|
||||
}
|
||||
catch (error) {
|
||||
if(kDebugMode) {
|
||||
log('ReverseNNRuStoreRemoteConfig.getEndScheduleDate - error - ${error.toString()}');
|
||||
}
|
||||
return DateTime(2025, 12, 31, 23, 59, 59, 999, 999);
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<Rule>?> getRules() async {
|
||||
try {
|
||||
FlutterRustoreRemoteconfig.init();
|
||||
final remoteConfig = await FlutterRustoreRemoteconfig.getRemoteConfig();
|
||||
final rules = remoteConfig.getString('scheduleRules');
|
||||
|
||||
return rules != null
|
||||
? (jsonDecode(rules) as List<dynamic>).map((el) => Rule.fromJson(el)).toList()
|
||||
: await _getRulesFromStorage();
|
||||
}
|
||||
catch(error) {
|
||||
if(kDebugMode) {
|
||||
log('ReverseNNRuStoreRemoteConfig.getRules - error - ${error.toString()}');
|
||||
}
|
||||
return await _getRulesFromStorage();
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<Rule>?> _getRulesFromStorage() async {
|
||||
final Map<String, dynamic>? schema = await _getSchemaFromStorage();
|
||||
if(schema == null || !schema.containsKey('rules')) return null;
|
||||
|
||||
return (schema['rules'] as List<dynamic>)
|
||||
.map((el) => Rule.fromJson(el))
|
||||
.toList();
|
||||
}
|
||||
|
||||
Future<List<ScheduleItem>?> getScheduleByKey(String key) async {
|
||||
try {
|
||||
FlutterRustoreRemoteconfig.init();
|
||||
final remoteConfig = await FlutterRustoreRemoteconfig.getRemoteConfig();
|
||||
final schedule = remoteConfig.getString('schedules-$key');
|
||||
|
||||
return schedule != null
|
||||
? (jsonDecode(schedule) as List<dynamic>)
|
||||
.map((el) => ScheduleItem.fromJson(el))
|
||||
.toList()
|
||||
: await _getScheduleByKeyFromStorage(key);
|
||||
}
|
||||
catch(error) {
|
||||
if(kDebugMode) {
|
||||
log('ReverseNNRuStoreRemoteConfig.getScheduleByKey($key) - error - ${error.toString()}');
|
||||
}
|
||||
return await _getScheduleByKeyFromStorage(key);
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<ScheduleItem>?> _getScheduleByKeyFromStorage(String key) async {
|
||||
final Map<String, dynamic>? schema = await _getSchemaFromStorage();
|
||||
if(
|
||||
schema == null
|
||||
|| !schema.containsKey('schedules')
|
||||
|| !(schema['schedules'] as Map<String, dynamic>).containsKey(key)
|
||||
) return null;
|
||||
|
||||
return (schema['schedules'][key] as List<dynamic>)
|
||||
.map((el) => ScheduleItem.fromJson(el))
|
||||
.toList();
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>?> _getSchemaFromStorage() async {
|
||||
return jsonDecode(await rootBundle.loadString('assets/schedule.json'));
|
||||
}
|
||||
}
|
||||
@@ -5,43 +5,25 @@ import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart' show DateFormat;
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:reverse_nn/application/dto/rule.dart';
|
||||
import 'package:reverse_nn/application/dto/schedule.dart';
|
||||
import 'package:reverse_nn/application/services/remote_config/service.dart';
|
||||
|
||||
class ScheduleService {
|
||||
static const Duration dayOffset = Duration(hours: 4);
|
||||
|
||||
Future<Map<String, dynamic>> getSchema() async {
|
||||
final source = await rootBundle
|
||||
.loadString('assets/schedule.json');
|
||||
return jsonDecode(source);
|
||||
}
|
||||
Future<Rule?> getRuleByDate(DateTime date) async {
|
||||
final List<Rule>? rules = await ReverseNNRuStoreRemoteConfig().getRules();
|
||||
if(rules == null) return null;
|
||||
|
||||
Future<Map<String, dynamic>?> getRule(DateTime day) async {
|
||||
final Map<String, dynamic> schema = await getSchema();
|
||||
if(!schema.containsKey('rules')) return null;
|
||||
|
||||
for(final Map<String, dynamic> rule in (schema['rules'] as List<dynamic>)) {
|
||||
final DateTime after = DateTime.parse(rule['after']);
|
||||
final DateTime? before = rule['before'] != null
|
||||
? DateTime.parse(rule['before'])
|
||||
: null;
|
||||
|
||||
if(day.isAfter(after) && (before == null || day.isBefore(before)))
|
||||
for(final Rule rule in rules) {
|
||||
if(date.isAfter(rule.after) && (rule.before == null || date.isBefore(rule.before!)))
|
||||
{ return rule; }
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<Map<String, String>?> getDataset(DateTime day) async {
|
||||
final Map<String, dynamic>? rule = await getRule(day);
|
||||
|
||||
if(rule == null || !rule.containsKey('dataset')) return null;
|
||||
|
||||
return (rule['dataset'] as Map<String, dynamic>).map((key, value) {
|
||||
return MapEntry(key, value.toString());
|
||||
});
|
||||
}
|
||||
|
||||
String datetimeWeekdayToDatasetKey(int weekday) {
|
||||
switch(weekday){
|
||||
case DateTime.monday: return 'monday';
|
||||
@@ -56,17 +38,7 @@ class ScheduleService {
|
||||
return 'monday';
|
||||
}
|
||||
|
||||
Future<List<Map<String, dynamic>>?> getScheduleByKey(String key) async {
|
||||
final Map<String, dynamic> schema = await getSchema();
|
||||
if(!schema.containsKey('schedules')) return null;
|
||||
if(!(schema['schedules'] as Map<String, dynamic>).containsKey(key)) return null;
|
||||
|
||||
return (schema['schedules'][key] as List<dynamic>).map((element) {
|
||||
return element as Map<String, dynamic>;
|
||||
}).toList();
|
||||
}
|
||||
|
||||
Future<List<Map<String, dynamic>>?> getScheduleByDate(DateTime datetime, {bool force = false}) async {
|
||||
Future<List<ScheduleItem>?> getScheduleByDate(DateTime datetime, {bool force = false}) async {
|
||||
final dateStart = datetime.copyWith(hour: 0, minute: 0, second: 0, microsecond: 0, millisecond: 0);
|
||||
final dateEnd = datetime.copyWith(hour: 23, minute: 59, second: 59, microsecond: 999, millisecond: 999);
|
||||
final datetimeStartWithOffset = dateStart.copyWith().add(dayOffset);
|
||||
@@ -75,7 +47,7 @@ class ScheduleService {
|
||||
? datetime
|
||||
: datetime.copyWith().subtract(const Duration(days: 1));
|
||||
|
||||
final Map<String, String>? dataset = await getDataset(usedScheduleDatetime);
|
||||
final Map<String, String>? dataset = (await getRuleByDate(usedScheduleDatetime))?.dataset;
|
||||
if(dataset == null) return null;
|
||||
|
||||
final String dayKey = DateFormat('y-M-d').format(usedScheduleDatetime);
|
||||
@@ -87,74 +59,55 @@ class ScheduleService {
|
||||
|
||||
if(scheduleKey == null) return null;
|
||||
|
||||
List<Map<String, dynamic>>? schedule = await getScheduleByKey(scheduleKey);
|
||||
List<ScheduleItem>? schedule = await ReverseNNRuStoreRemoteConfig().getScheduleByKey(scheduleKey);
|
||||
if(schedule == null) return null;
|
||||
|
||||
int durationOffset = 0;
|
||||
for (var i = 0; i < schedule.length; i++) {
|
||||
final scheduleItem = schedule[i];
|
||||
final int duration = (scheduleItem['duration'] as int);
|
||||
final ScheduleItem scheduleItem = schedule[i];
|
||||
DateTime start = datetimeStartWithOffset.copyWith().add(Duration(minutes: durationOffset));
|
||||
DateTime end = datetimeStartWithOffset.copyWith().add(Duration(minutes: durationOffset + duration));
|
||||
durationOffset += duration;
|
||||
DateTime end = datetimeStartWithOffset.copyWith().add(Duration(minutes: durationOffset + scheduleItem.duration));
|
||||
durationOffset += scheduleItem.duration;
|
||||
|
||||
if(!force) {
|
||||
if(i == 0) {
|
||||
final schedulePrevDay = await getScheduleByDate(datetime.copyWith().subtract(const Duration(days: 1)), force: true);
|
||||
final lastScheduleElement = schedulePrevDay?.last;
|
||||
if(lastScheduleElement != null && (lastScheduleElement['direction'] as String) == (scheduleItem['direction'] as String)) {
|
||||
start = start.subtract(Duration(minutes: lastScheduleElement['duration'] as int));
|
||||
if(lastScheduleElement != null && lastScheduleElement.direction == scheduleItem.direction) {
|
||||
start = start.subtract(Duration(minutes: lastScheduleElement.duration));
|
||||
}
|
||||
}
|
||||
|
||||
if(i == (schedule.length -1)) {
|
||||
final scheduleNextDay = await getScheduleByDate(datetime.copyWith().add(const Duration(days: 1)), force: true);
|
||||
final firstScheduleElement = scheduleNextDay?.first;
|
||||
if(firstScheduleElement != null && (firstScheduleElement['direction'] as String) == (scheduleItem['direction'] as String)) {
|
||||
end = end.add(Duration(minutes: firstScheduleElement['duration'] as int));
|
||||
if(firstScheduleElement != null && firstScheduleElement.direction == scheduleItem.direction) {
|
||||
end = end.add(Duration(minutes: firstScheduleElement.duration));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
schedule[i]['start'] = start;
|
||||
schedule[i]['show_start_date'] = !(start.isAfter(dateStart) && start.isBefore(dateEnd));
|
||||
schedule[i]['end'] = end;
|
||||
schedule[i]['show_end_date'] = !(end.isAfter(dateStart) && end.isBefore(dateEnd));
|
||||
schedule[i] = scheduleItem.fillAdditional(
|
||||
start: start,
|
||||
end: end,
|
||||
showStartDate: !(start.isAfter(dateStart) && start.isBefore(dateEnd)),
|
||||
showEndDate: !(end.isAfter(dateStart) && end.isBefore(dateEnd))
|
||||
);
|
||||
}
|
||||
|
||||
return schedule;
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>?> getCurrentStatus() async {
|
||||
Future<ScheduleItem?> getCurrentStatus() async {
|
||||
final DateTime now = DateTime.now();
|
||||
final List<Map<String, dynamic>>? schedule = await getScheduleByDate(now);
|
||||
final List<ScheduleItem>? schedule = await getScheduleByDate(now);
|
||||
if(schedule == null) return null;
|
||||
|
||||
for(var i = 0; i < schedule.length; i++) {
|
||||
final start = schedule[i]['start'];
|
||||
final end = schedule[i]['end'];
|
||||
|
||||
if(now.isAfter(start) && now.isBefore(end)) {
|
||||
return schedule[i];
|
||||
}
|
||||
for(final ScheduleItem item in schedule) {
|
||||
if(item.start == null || item.end == null) continue;
|
||||
if(now.isAfter(item.start!) && now.isBefore(item.end!)) return item;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static String formatDirection(String direction) {
|
||||
switch(direction) {
|
||||
case 'in_city': return 'В город';
|
||||
case 'out_city': return 'Из города';
|
||||
default: return 'Переключение';
|
||||
}
|
||||
}
|
||||
|
||||
static IconData getIconByDirection(String? direction) {
|
||||
switch(direction) {
|
||||
case 'in_city': return Icons.input_outlined;
|
||||
case 'out_city': return Icons.output_outlined;
|
||||
default: return Icons.change_circle_outlined;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
lib/configuration.dart
Normal file
3
lib/configuration.dart
Normal file
@@ -0,0 +1,3 @@
|
||||
class Configuration {
|
||||
static const String ruStoreRemoteConfigAppID = '12cbda1f-4601-4f6d-924d-64a210005e96';
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
enum Direction {
|
||||
inCity(displayName: 'В город'),
|
||||
change(displayName: 'Переключение'),
|
||||
outCity(displayName: 'Из города');
|
||||
|
||||
const Direction({
|
||||
required this.displayName
|
||||
});
|
||||
|
||||
final String displayName;
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
import 'package:reverse_nn/enums/direction.dart';
|
||||
import 'package:sprintf/sprintf.dart';
|
||||
|
||||
enum Schedule {
|
||||
daily(elements: [
|
||||
ScheduleElement(startHours: 4, startMinutes: 0, duration: 415, direction: Direction.inCity),
|
||||
ScheduleElement(startHours: 10, startMinutes: 55, duration: 5, direction: Direction.change),
|
||||
ScheduleElement(startHours: 11, startMinutes: 0, duration: 115, direction: Direction.outCity),
|
||||
ScheduleElement(startHours: 12, startMinutes: 55, duration: 5, direction: Direction.change),
|
||||
ScheduleElement(startHours: 13, startMinutes: 0, duration: 145, direction: Direction.inCity),
|
||||
ScheduleElement(startHours: 15, startMinutes: 25, duration: 5, direction: Direction.change),
|
||||
ScheduleElement(startHours: 15, startMinutes: 30, duration: 205, direction: Direction.outCity),
|
||||
ScheduleElement(startHours: 18, startMinutes: 55, duration: 5, direction: Direction.change),
|
||||
ScheduleElement(startHours: 19, startMinutes: 0, duration: 55, direction: Direction.inCity),
|
||||
ScheduleElement(startHours: 19, startMinutes: 55, duration: 5, direction: Direction.change),
|
||||
ScheduleElement(startHours: 20, startMinutes: 0, duration: 475, direction: Direction.outCity),
|
||||
ScheduleElement(startHours: 3, startMinutes: 55, duration: 5, direction: Direction.change),
|
||||
]),
|
||||
friday(elements: [
|
||||
ScheduleElement(startHours: 4, startMinutes: 0, duration: 415, direction: Direction.inCity),
|
||||
ScheduleElement(startHours: 10, startMinutes: 55, duration: 5, direction: Direction.change),
|
||||
ScheduleElement(startHours: 11, startMinutes: 0, duration: 115, direction: Direction.outCity),
|
||||
ScheduleElement(startHours: 12, startMinutes: 55, duration: 5, direction: Direction.change),
|
||||
ScheduleElement(startHours: 13, startMinutes: 0, duration: 55, direction: Direction.inCity),
|
||||
ScheduleElement(startHours: 13, startMinutes: 55, duration: 5, direction: Direction.change),
|
||||
ScheduleElement(startHours: 14, startMinutes: 0, duration: 840, direction: Direction.outCity),
|
||||
]),
|
||||
saturday(elements: [
|
||||
ScheduleElement(startHours: 4, startMinutes: 0, duration: 655, direction: Direction.outCity),
|
||||
ScheduleElement(startHours: 14, startMinutes: 55, duration: 5, direction: Direction.change),
|
||||
ScheduleElement(startHours: 15, startMinutes: 0, duration: 175, direction: Direction.inCity),
|
||||
ScheduleElement(startHours: 17, startMinutes: 55, duration: 5, direction: Direction.change),
|
||||
ScheduleElement(startHours: 18, startMinutes: 0, duration: 115, direction: Direction.outCity),
|
||||
ScheduleElement(startHours: 19, startMinutes: 55, duration: 5, direction: Direction.change),
|
||||
ScheduleElement(startHours: 20, startMinutes: 0, duration: 115, direction: Direction.inCity),
|
||||
ScheduleElement(startHours: 21, startMinutes: 55, duration: 5, direction: Direction.change),
|
||||
ScheduleElement(startHours: 22, startMinutes: 0, duration: 355, direction: Direction.outCity),
|
||||
ScheduleElement(startHours: 3, startMinutes: 55, duration: 5, direction: Direction.change),
|
||||
]),
|
||||
sunday(elements: [
|
||||
ScheduleElement(startHours: 4, startMinutes: 0, duration: 235, direction: Direction.inCity),
|
||||
ScheduleElement(startHours: 7, startMinutes: 55, duration: 5, direction: Direction.change),
|
||||
ScheduleElement(startHours: 8, startMinutes: 0, duration: 175, direction: Direction.outCity),
|
||||
ScheduleElement(startHours: 10, startMinutes: 55, duration: 5, direction: Direction.change),
|
||||
ScheduleElement(startHours: 11, startMinutes: 0, duration: 1020, direction: Direction.inCity),
|
||||
]);
|
||||
|
||||
const Schedule({required this.elements});
|
||||
|
||||
final List<ScheduleElement> elements;
|
||||
}
|
||||
|
||||
class ScheduleElement {
|
||||
final int startHours;
|
||||
final int startMinutes;
|
||||
|
||||
final int duration;
|
||||
final Direction direction;
|
||||
|
||||
const ScheduleElement({required this.startHours, required this.startMinutes, required this.duration, required this.direction});
|
||||
|
||||
String getStartedTimeString() { return sprintf('%02i:%02i', [startHours, startMinutes]); }
|
||||
String getEndedTimeString() {
|
||||
DateTime e = DateTime(2024, 8, 1, startHours, startMinutes).add(Duration(minutes: duration)).subtract(const Duration(microseconds: 1));
|
||||
return sprintf('%02i:%02i', [e.hour, e.minute]);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get_storage/get_storage.dart';
|
||||
import 'package:reverse_nn/application.dart';
|
||||
import 'package:reverse_nn/application/services/remote_config/service.dart';
|
||||
|
||||
void main() async {
|
||||
await GetStorage.init();
|
||||
ReverseNNRuStoreRemoteConfig().create();
|
||||
runApp(const ReversNNApplication());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:reverse_nn/widgets/schedule_widget.dart';
|
||||
|
||||
class HomePage extends StatelessWidget {
|
||||
const HomePage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
||||
title: const Text('Реверс НН'),
|
||||
),
|
||||
body: const ScheduleWidget()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart' show DateFormat;
|
||||
import 'package:reverse_nn/application/services/schedule.dart';
|
||||
import 'package:reverse_nn/application/dto/schedule.dart';
|
||||
|
||||
class ScheduleItemComponent extends StatelessWidget {
|
||||
final Map<String, dynamic> item;
|
||||
final ScheduleItem item;
|
||||
const ScheduleItemComponent({super.key, required this.item});
|
||||
|
||||
@override
|
||||
@@ -20,7 +20,7 @@ class ScheduleItemComponent extends StatelessWidget {
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Icon(ScheduleService.getIconByDirection(item['direction'] as String), size: 56),
|
||||
Icon(item.direction.icon(), size: 56),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
@@ -41,17 +41,17 @@ class ScheduleItemComponent extends StatelessWidget {
|
||||
}
|
||||
|
||||
Widget _directionText(BuildContext context) => Text(
|
||||
ScheduleService.formatDirection(item['direction'] ?? ''),
|
||||
item.direction.displayName(),
|
||||
style: Theme.of(context).textTheme.headlineLarge
|
||||
);
|
||||
|
||||
Widget _startText(BuildContext context) => Text(
|
||||
'C\t\t\t\t${formatDate(item['start'], showDate: item['show_start_date'] ?? false)}',
|
||||
'C\t\t\t\t${formatDate(item.start!, showDate: item.showStartDate ?? false)}',
|
||||
style: Theme.of(context).textTheme.titleLarge
|
||||
);
|
||||
|
||||
Widget _endText(BuildContext context) => Text(
|
||||
'До\t${formatDate(item['end'], showDate: item['show_end_date'] ?? false)}',
|
||||
'До\t${formatDate(item.end!, showDate: item.showEndDate ?? false)}',
|
||||
style: Theme.of(context).textTheme.titleLarge
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:reverse_nn/application/controllers/calendar_schedule_controller.dart';
|
||||
import 'package:reverse_nn/application/services/schedule.dart';
|
||||
import 'package:reverse_nn/application/services/remote_config/service.dart';
|
||||
import 'package:reverse_nn/ui/components/schedule_item_component.dart';
|
||||
import 'package:reverse_nn/ui/layouts/application_layout.dart';
|
||||
import 'package:intl/intl.dart' show DateFormat;
|
||||
@@ -114,11 +114,14 @@ class _SelectedDateWidget extends StatelessWidget {
|
||||
|
||||
void _openCalendar(BuildContext context) async {
|
||||
DateTime now = DateTime.now();
|
||||
DateTime firstDate = await ReverseNNRuStoreRemoteConfig().getStartScheduleDate();
|
||||
DateTime lastDate = await ReverseNNRuStoreRemoteConfig().getEndScheduleDate();
|
||||
|
||||
DateTime? picked = await showDatePicker(
|
||||
context: context,
|
||||
initialDate: now,
|
||||
firstDate: DateTime(2024, 8, 1, 12),
|
||||
lastDate: DateTime(2025, 12, 31, 12),
|
||||
firstDate: firstDate,
|
||||
lastDate: lastDate,
|
||||
locale: const Locale('ru')
|
||||
);
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_rustore_remoteconfig/flutter_rustore_remoteconfig.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:reverse_nn/application/controllers/calendar_schedule_controller.dart';
|
||||
import 'package:reverse_nn/application/controllers/home_controller.dart';
|
||||
@@ -8,6 +10,7 @@ import 'package:reverse_nn/application/services/schedule.dart';
|
||||
import 'package:reverse_nn/ui/components/current_status_component.dart';
|
||||
import 'package:reverse_nn/ui/components/grid_menu_item.dart';
|
||||
import 'package:reverse_nn/ui/layouts/application_layout.dart';
|
||||
import 'package:reverse_nn/application/services/remote_config/service.dart';
|
||||
|
||||
class HomeScreen extends GetWidget<HomeController> {
|
||||
const HomeScreen({super.key});
|
||||
@@ -29,8 +32,9 @@ class HomeScreen extends GetWidget<HomeController> {
|
||||
mainAxisSpacing: 10,
|
||||
crossAxisSpacing: 10,
|
||||
),
|
||||
children: const [
|
||||
GridMenuItem(icon: Icons.calendar_month, label: 'Расписание', onTap: CalendarScheduleController.openScreen),
|
||||
children: [
|
||||
const GridMenuItem(icon: Icons.calendar_month, label: 'Расписание', onTap: CalendarScheduleController.openScreen),
|
||||
if(kDebugMode) GridMenuItem(icon: Icons.android, label: 'DEBUG', onTap: _debugRuStore),
|
||||
// const GridMenuItem(icon: Icons.monetization_on, label: 'Поддержать автора'),
|
||||
// GridMenuItem(),
|
||||
// GridMenuItem(),
|
||||
@@ -41,4 +45,10 @@ class HomeScreen extends GetWidget<HomeController> {
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
void _debugRuStore() async {
|
||||
ReverseNNRuStoreRemoteConfig().getEndScheduleDate().then((value) {
|
||||
log(value.toIso8601String());
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
import 'package:reverse_nn/enums/schedule.dart';
|
||||
|
||||
class Scheduler {
|
||||
static Schedule getSchedule(DateTime date) {
|
||||
switch(date.weekday) {
|
||||
case DateTime.friday: return Schedule.friday;
|
||||
case DateTime.saturday: return Schedule.saturday;
|
||||
case DateTime.sunday: return Schedule.sunday;
|
||||
|
||||
default: return Schedule.daily;
|
||||
}
|
||||
}
|
||||
|
||||
static List<ScheduleElement> getScheduleList() {
|
||||
List<ScheduleElement> result = List<ScheduleElement>.empty(growable: true);
|
||||
|
||||
DateTime now = DateTime.now();
|
||||
DateTime startSchedule = now.hour < 4 ? now.subtract(const Duration(days: 1)) : now;
|
||||
|
||||
bool currentReached = false;
|
||||
for (ScheduleElement element in [...Scheduler.getSchedule(startSchedule).elements, ...Scheduler.getSchedule(startSchedule.add(const Duration(days: 1))).elements]) {
|
||||
if(!currentReached) {
|
||||
DateTime s = DateTime(now.year, now.month, now.day, element.startHours, element.startMinutes, 0);
|
||||
if(now.compareTo(startSchedule) != 0 && element.startHours >= 4) { s = s.subtract(const Duration(days: 1)); }
|
||||
DateTime e = s.add(Duration(minutes: element.duration)).subtract(const Duration(microseconds: 1));
|
||||
|
||||
if(now.isAfter(s) && now.isBefore(e)) { currentReached = true; }
|
||||
else { continue; }
|
||||
}
|
||||
|
||||
result.add(element);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class LoaderWidget extends StatelessWidget {
|
||||
const LoaderWidget({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
CircularProgressIndicator()
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:reverse_nn/enums/direction.dart';
|
||||
import 'package:reverse_nn/enums/schedule.dart';
|
||||
import 'package:sprintf/sprintf.dart';
|
||||
|
||||
class CurrentReversWidget extends StatelessWidget {
|
||||
const CurrentReversWidget({super.key, required this.scheduleElement});
|
||||
|
||||
final ScheduleElement scheduleElement;
|
||||
|
||||
IconData _getIconData() {
|
||||
switch(scheduleElement.direction) {
|
||||
case Direction.inCity: return Icons.arrow_upward;
|
||||
case Direction.outCity: return Icons.arrow_downward;
|
||||
case Direction.change: return Icons.cancel_outlined;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(8.0)),
|
||||
color: Theme.of(context).colorScheme.primaryContainer
|
||||
),
|
||||
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
|
||||
children: [
|
||||
Icon(_getIconData(), size: 56.0),
|
||||
const SizedBox(width: 10),
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Реверс: ${scheduleElement.direction.displayName}', style: const TextStyle(fontSize: 20)),
|
||||
Text('${scheduleElement.getStartedTimeString()} - ${scheduleElement.getEndedTimeString()}', style: const TextStyle(fontSize: 36)),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ScheduledReversWidget extends StatelessWidget {
|
||||
const ScheduledReversWidget({super.key, required this.scheduleElement});
|
||||
|
||||
final ScheduleElement scheduleElement;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
margin: const EdgeInsets.symmetric(horizontal: 8),
|
||||
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(8.0)),
|
||||
color: Theme.of(context).colorScheme.secondaryContainer
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Text(sprintf('Следующий статус в %02i:%02i - %s', [
|
||||
scheduleElement.startHours,
|
||||
scheduleElement.startMinutes,
|
||||
scheduleElement.direction.displayName
|
||||
])),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:reverse_nn/enums/schedule.dart';
|
||||
import 'package:reverse_nn/utils/scheduler.dart';
|
||||
import 'package:reverse_nn/widgets/loader_widget.dart';
|
||||
import 'package:reverse_nn/widgets/schedule_element_widget.dart';
|
||||
|
||||
class ScheduleWidget extends StatefulWidget {
|
||||
const ScheduleWidget({super.key});
|
||||
|
||||
@override
|
||||
State<ScheduleWidget> createState() => _ScheduleWidgetState();
|
||||
}
|
||||
|
||||
class _ScheduleWidgetState extends State<ScheduleWidget> {
|
||||
bool _loading = true;
|
||||
List<ScheduleElement> _schedule = List.empty();
|
||||
|
||||
void loadScheduleData() async {
|
||||
setState(() { _loading = true; });
|
||||
setState(() { _schedule = Scheduler.getScheduleList(); });
|
||||
setState(() { _loading = false; });
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
loadScheduleData();
|
||||
|
||||
Future.delayed(const Duration(seconds: 15), () => loadScheduleData());
|
||||
|
||||
return _loading && _schedule.isNotEmpty ? const LoaderWidget() : ListView.separated(
|
||||
scrollDirection: Axis.vertical,
|
||||
shrinkWrap: true,
|
||||
padding: const EdgeInsets.all(10),
|
||||
separatorBuilder: (BuildContext context, int index) {
|
||||
return SizedBox(height: index == 0 ? 10 : 4);
|
||||
},
|
||||
itemCount: _schedule.length,
|
||||
itemBuilder: (ctx, i) {
|
||||
if(i == 0) { return CurrentReversWidget(scheduleElement: _schedule[i]); }
|
||||
return ScheduledReversWidget(scheduleElement: _schedule[i]);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
335
pubspec.lock
335
pubspec.lock
@@ -1,6 +1,27 @@
|
||||
# Generated by pub
|
||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||
packages:
|
||||
_fe_analyzer_shared:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: _fe_analyzer_shared
|
||||
sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "72.0.0"
|
||||
_macros:
|
||||
dependency: transitive
|
||||
description: dart
|
||||
source: sdk
|
||||
version: "0.3.2"
|
||||
analyzer:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: analyzer
|
||||
sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.7.0"
|
||||
archive:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -33,6 +54,70 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
build:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build
|
||||
sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
build_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_config
|
||||
sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
build_daemon:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_daemon
|
||||
sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.2"
|
||||
build_resolvers:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_resolvers
|
||||
sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.2"
|
||||
build_runner:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: build_runner
|
||||
sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.13"
|
||||
build_runner_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_runner_core
|
||||
sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.3.2"
|
||||
built_collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: built_collection
|
||||
sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.1.1"
|
||||
built_value:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: built_value
|
||||
sha256: "28a712df2576b63c6c005c465989a348604960c0958d28be5303ba9baa841ac2"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.9.3"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -65,6 +150,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
code_builder:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: code_builder
|
||||
sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.10.1"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -73,6 +166,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.18.0"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: convert
|
||||
sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.2"
|
||||
crypto:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -89,6 +190,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.8"
|
||||
dart_style:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: dart_style
|
||||
sha256: "7856d364b589d1f08986e140938578ed36ed948581fbc3bc9aef1805039ac5ab"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.7"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -105,6 +214,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.3"
|
||||
file:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file
|
||||
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.1"
|
||||
fixnum:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fixnum
|
||||
sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
@@ -131,11 +256,27 @@ packages:
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_rustore_remoteconfig:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_rustore_remoteconfig
|
||||
sha256: f5dfccc3f4270bcd3fdadccc2c79514cd0db9b56103f92b0f7af19a79acab5b8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.0"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
frontend_server_client:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: frontend_server_client
|
||||
sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
get:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -152,6 +293,38 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
glob:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: glob
|
||||
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
graphs:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: graphs
|
||||
sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
http_multi_server:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http_multi_server
|
||||
sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.2"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http_parser
|
||||
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.2"
|
||||
image:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -168,14 +341,38 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.19.0"
|
||||
json_annotation:
|
||||
io:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: io
|
||||
sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.5"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: js
|
||||
sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.1"
|
||||
json_annotation:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: json_annotation
|
||||
sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.9.0"
|
||||
json_serializable:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: json_serializable
|
||||
sha256: c2fcb3920cf2b6ae6845954186420fca40bc0a8abcc84903b7801f17d7050d7c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.9.0"
|
||||
leak_tracker:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -208,6 +405,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
logging:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: logging
|
||||
sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
macros:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: macros
|
||||
sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.2-main.4"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -232,6 +445,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.15.0"
|
||||
mime:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: mime
|
||||
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
package_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: package_config
|
||||
sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -312,11 +541,67 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.8"
|
||||
pool:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pool
|
||||
sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.5.1"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pub_semver
|
||||
sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.5"
|
||||
pubspec_parse:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pubspec_parse
|
||||
sha256: "81876843eb50dc2e1e5b151792c9a985c5ed2536914115ed04e9c8528f6647b0"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
shelf:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf
|
||||
sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.1"
|
||||
shelf_web_socket:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf_web_socket
|
||||
sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.99"
|
||||
source_gen:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_gen
|
||||
sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.5.0"
|
||||
source_helper:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_helper
|
||||
sha256: "86d247119aedce8e63f4751bd9626fc9613255935558447569ad42f9f5b48b3c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.5"
|
||||
source_span:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -349,6 +634,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
stream_transform:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stream_transform
|
||||
sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
string_scanner:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -373,6 +666,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.2"
|
||||
timing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: timing
|
||||
sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -397,6 +698,38 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "14.2.5"
|
||||
watcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: watcher
|
||||
sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web
|
||||
sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
web_socket:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web_socket
|
||||
sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.6"
|
||||
web_socket_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web_socket_channel
|
||||
sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
# In Windows, build-name is used as the major, minor, and patch parts
|
||||
# of the product and file versions while build-number is used as the build suffix.
|
||||
version: 1.1.0+3
|
||||
version: 1.1.1+4
|
||||
|
||||
environment:
|
||||
sdk: '>=3.3.3 <4.0.0'
|
||||
@@ -41,6 +41,8 @@ dependencies:
|
||||
get: ^4.6.6
|
||||
get_storage: ^2.1.1
|
||||
sprintf: "^7.0.0"
|
||||
flutter_rustore_remoteconfig: ^7.0.0
|
||||
json_annotation: ^4.9.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
@@ -53,6 +55,8 @@ dev_dependencies:
|
||||
# rules and activating additional ones.
|
||||
flutter_lints: ^3.0.0
|
||||
flutter_launcher_icons: "^0.13.1"
|
||||
json_serializable: ^6.9.0
|
||||
build_runner: ^2.4.13
|
||||
|
||||
flutter_launcher_icons:
|
||||
android: "launcher_icon"
|
||||
|
||||
Reference in New Issue
Block a user