DartUp 2020 ( ). , , , , , – .
?
– . . , – , , , . Android iOS, Flutter. .
, .
-, B2B- , : , , , .
, . -, UI, - ( Material Design Cupertino Design, ). , , . -, , .. , . , , .
. , .
API. DTO . , . . – , .
, – " ", – "", – " ". - ( / ).
– . -. , API. , , ( , – ), . , , - API DTO . , .
. Flutter. - , "" , .
BLoC
BLoC. , , : UI- ( , ) BLoC (Business Logic Component, -). BLoC – , ( UI, BLoC). BLoC , , , UI ( ) BLoC:
Redux (, ), : , store . BLoC', "-".
, – , , - , :
, - ( , , ) .
BLoC bloc. , , .
BLoC' ( ).
: BlocA
, BlocB
, BlocB
BlocA
. , , BlocA
BLoC'. BlocA
Stream<StateB>
( Sink<EventB>
, - BlocB
). , BlocB
( Stream<StateB>
Sink<EventB>
), BlocA
, StateB
. , , Stream<StateB>
BlocB
.
flutter_bloc
, : , BLoC ViewModel, UI-, , . , , UI UI. BLoC ( , -, ).
, – UI BLoC – : , - Flutter', GUI , CLI. , , UI-, BLoC' .
, .
, , , , . ( , Dart – ), , , .
: . , , , , .
– . ( , ).
, . , BLoC' (aka sealed classes – , ). – . - throw
. Either<E, R>
, , , . , , .
( , ), - , NNBD , - null
. , , - non-nullable, " " Optional<T>
.
. , , ; , .
-, freezed – , , - sealed Dart'.
- :
@freezed
abstract class TasksEvent with _$TasksEvent {
const factory TasksEvent.fetchRequested() = FetchRequested;
const factory TasksEvent.fetchCompleted(Either<Exception, TasksData> result) =
FetchCompleted;
const factory TasksEvent.filtersUpdated(TaskFilters filters) = FiltersUpdated;
const factory TasksEvent.taskUpdated(Task task) = TaskUpdated;
const factory TasksEvent.taskCreated(Task task) = TaskCreated;
const factory TasksEvent.taskResolved(Task task) = TaskResolved;
}
, TasksBloc
. , TasksBloc
, , map
:
@override
Stream<TasksState> mapEventToState(TasksEvent event) => event.map(
fetchRequested: _mapFetchRequested,
fetchCompleted: _mapFetchCompleted,
filtersUpdated: _mapFiltersUpdated,
taskUpdated: _mapTaskUpdated,
taskCreated: _mapTaskCreated,
taskResolved: _mapTaskResolved,
);
Stream<TasksState> _mapTaskCreated(TaskCreated event) async* {
// ...
}
( ) , , .
, , , . .
, , BuiltMap
BuiltList
+ , Builder.
- :
yield state.copyWith(
tasks: state.tasks.rebuild((b) => b[createdTask.id] = createdTask),
);
, BLoC. - :
@freezed
abstract class TasksState implements _$TasksState {
const factory TasksState({
@required ProcessingState<TaskFetchingError, EmptyResult> fetchingState,
@required ProcessingState<Exception, EmptyResult> updateState,
@required BuiltList<Department> departments,
@required TaskFilters filters,
@required BuiltMap<TaskId, Task> tasks,
}) = _TasksState;
const TasksState._();
}
@freezed
abstract class TasksEvent with _$TasksEvent {
const factory TasksEvent.fetchRequested() = FetchRequested;
const factory TasksEvent.fetchCompleted(Either<Exception, TasksData> result) =
FetchCompleted;
const factory TasksEvent.filtersUpdated(TaskFilters filters) = FiltersUpdated;
const factory TasksEvent.taskUpdated(Task task) = TaskUpdated;
const factory TasksEvent.taskCreated(Task task) = TaskCreated;
const factory TasksEvent.taskResolved(Task task) = TaskResolved;
}
class TasksBloc extends Bloc<TasksEvent, TasksState> {
@override
TasksState get initialState => TasksState(
tasks: BuiltMap<TaskId, Task>(),
departments: BuiltList<Department>(),
filters: TaskFilters());
@override
Stream<TasksState> mapEventToState(TasksEvent event) => event.map(
fetchRequested: _mapFetchRequested,
fetchCompleted: _mapFetchCompleted,
filtersUpdated: _mapFiltersUpdated,
taskUpdated: _mapTaskUpdated,
taskCreated: _mapTaskCreated,
taskResolved: _mapTaskResolved,
);
Stream<TasksState> _mapTaskCreated(TaskCreated event) async* {
yield state.copyWith(updateState: const ProcessingState.loading());
final result = await _createTask(event.task);
yield* result.fold(
_triggerUpdateError,
(taskId) async* {
final createdTask = event.task.copyWith(id: taskId);
yield state.copyWith(
tasks: state.tasks.rebuild((b) => b[createdTask.id] = createdTask),
);
yield* _triggerUpdateSuccess();
},
);
}
// ...
}
_mapTaskCreated
: "", _createTask
. , .
Either<Exception, TaskId>
, "", "", .
API. , , / DTO / Dart-.
, DTO :
@JsonSerializable()
class GetAllTasksRequest {
GetAllTasksRequest({
this.assigneeProfileIds,
this.departmentIds,
this.createdUtc,
this.deadlineUtc,
this.closedUtc,
this.state,
this.extent,
});
final List<String> assigneeProfileIds;
final List<String> departmentIds;
final TimePeriodDto createdUtc;
final TimePeriodDto deadlineUtc;
final TimePeriodDto closedUtc;
final TaskStateFilter state;
final ExtentDto extent;
Map<String, dynamic> toJson() => _$GetAllTasksRequestToJson(this);
}
API.
Android, . – , , :
@RestApi()
abstract class RestClient {
factory RestClient(Dio dio) = _RestClient;
@anonymous
@POST('/api/general/v1/users/signIn')
Future<SignInResponse> signIn(@Body() SignInRequest request);
@anonymous
@POST('/api/general/v1/users/resetPassword')
Future<EmptyResponse> resetPassword(
@Body() ResetPasswordRequestDto request,
);
@POST('/api/commander/v1/tasks/getAll')
Future<GetAllTasksResponseDto> getTasks(@Body() GetAllTasksRequest request);
@POST('/api/commander/v1/tasks/add')
Future<TaskDto> createTask(@Body() CreateTaskDto request);
}
const anonymous = Extra({'isAnonymous': true});
, , .
– , , : , , ..
Dart', dartfmt
, . , , ", dartfmt
". , , ( ). , CI-, PR' . , , 80 . :
“…for chrissake, don’t try to make 80 columns some immovable standard.”
Linus Torvalds
, dartfmt
-l
( , lines_longer_than_80_chars
). , 120 – .
Dart' – . , . – .
, / (//).
, , , ( , , , ); , CI- PR.
, :
pedantic – ;
effective_dart – Effective Dart;
mews_pedantic – .
CI/CD
CI/CD, : " , ". Azure Pipelines ( ), , , Flutter, . , , Flutter', . – YAML bash-.
, Flutter', - :
, Appcircle, Bitrise Codemagic AWS device farm – .. UI- ( ).
- Codemagic – , .
GitHub Actions, , Azure Pipelines – Flutter. 500 MB 2.000 , : macOS ( , , iOS), 10! .., macOS-, 2.000 , 200.
Flutter.
– . Dart' , . , , . , sentry.
, , Flutter – - , . , Flutter . , , ( ). , – - Flutter .
text ellipsizing ( - ?) , , .
( , , ) – NoSuchMethodError
(, Java NullPointerException
). , , Flutter' , – , .
( ). , ( , iOS ). , : " ? IDE ? flutter clean
? ?" – . , , , ( , Xcode).
, ?
. " "? , ? ?
, . . , Google . Flutter . UI – UI- Android-, . ...
: 4 ( ). , , . Android-, Flutter . , , ( ).
, Dart'. Kotlin', . , - . ( , UI) . Flutter' , , 1,5 – .
Flutter, , . , . Flutter – , , .