import 'dart:async';
import 'dart:convert';
+import 'package:flutter/material.dart';
+import 'package:pve_flutter_frontend/bloc/proxmox_base_bloc.dart';
+import 'package:pve_flutter_frontend/states/proxmox_form_field_state.dart';
import 'package:meta/meta.dart';
-import 'package:pve_flutter_frontend/events/pve_guest_id_selector_events.dart';
-import 'package:pve_flutter_frontend/states/pve_guest_id_selector_states.dart';
import 'package:rxdart/rxdart.dart';
import 'package:proxmox_dart_api_client/proxmox_dart_api_client.dart'
as proxclient;
-class PveGuestIdSelectorBloc {
+class PveGuestIdSelectorBloc
+ extends ProxmoxBaseBloc<PveGuestIdSelectorEvent, GuestIdSelectorState> {
final proxclient.Client apiClient;
- final PublishSubject<PveGuestIdSelectorEvent> _eventSubject =
- PublishSubject<PveGuestIdSelectorEvent>();
- BehaviorSubject<PveGuestIdSelectorState> _stateSubject;
- StreamSink<PveGuestIdSelectorEvent> get events => _eventSubject.sink;
- Stream<PveGuestIdSelectorState> get state => _stateSubject.stream;
+ @override
+ GuestIdSelectorState get initialState => GuestIdSelectorState();
- PveGuestIdSelectorBloc({@required this.apiClient}) {
- _stateSubject = BehaviorSubject<PveGuestIdSelectorState>();
- _eventSubject
- .debounceTime(Duration(milliseconds: 250))
- .switchMap((event) => _eventToState(event))
- .forEach((PveGuestIdSelectorState state) {
- _stateSubject.add(state);
- });
+ PveGuestIdSelectorBloc({@required this.apiClient});
+
+ @override
+ Stream<GuestIdSelectorState> eventPipe(
+ PublishSubject<PveGuestIdSelectorEvent> events,
+ Stream<GuestIdSelectorState> pipeInto(PveGuestIdSelectorEvent event),
+ ) {
+ return events.debounceTime(Duration(milliseconds: 150)).switchMap(pipeInto);
}
- Stream<PveGuestIdSelectorState> _eventToState(
+ @override
+ Stream<GuestIdSelectorState> processEvents(
PveGuestIdSelectorEvent event) async* {
- print(event);
-
- if (event is LoadNextFreeId) {
- final id = await getNextFreeID();
- yield PveGuestIdSelectorState(id: id);
+ if (event is PrefetchId) {
+ try {
+ final id = await getNextFreeID();
+ yield GuestIdSelectorState(value: id);
+ } on proxclient.ProxmoxApiException catch (e) {
+ yield GuestIdSelectorState(value: null, errorText: "Could not load ID");
+ }
}
-
- if (event is ValidateInput) {
+ if (event is OnChanged) {
if (event.id == "") {
- yield PveGuestIdSelectorState(id: event.id, error: "Input required");
+ yield GuestIdSelectorState(
+ value: event.id, errorText: "Input required");
return;
}
try {
final id = await getNextFreeID(id: event.id);
- yield PveGuestIdSelectorState(id: id);
+ yield GuestIdSelectorState(value: id);
} on proxclient.ProxmoxApiException catch (e) {
if (e.details != null && e.details['vmid'] != null) {
- yield PveGuestIdSelectorState(id: event.id, error: e.details['vmid']);
+ yield GuestIdSelectorState(
+ value: event.id, errorText: e.details['vmid']);
}
}
}
}
- void dispose() {
- _eventSubject.close();
- _stateSubject.close();
- }
-
Future<String> getNextFreeID({String id}) async {
var url = Uri.parse(
proxclient.getPlatformAwareOrigin() + '/api2/json/cluster/nextid');
return jsonBody['data'];
}
}
+
+abstract class PveGuestIdSelectorEvent {}
+
+class PrefetchId extends PveGuestIdSelectorEvent {}
+
+class OnChanged extends PveGuestIdSelectorEvent {
+ final String id;
+
+ OnChanged(this.id);
+}
+
+class GuestIdSelectorState extends PveFormFieldState<String> {
+ GuestIdSelectorState({String value, String errorText})
+ : super(value: value, errorText: errorText);
+}
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import 'package:pve_flutter_frontend/bloc/pve_guest_id_selector_bloc.dart';
-import 'package:pve_flutter_frontend/events/pve_guest_id_selector_events.dart';
-import 'package:pve_flutter_frontend/states/pve_guest_id_selector_states.dart';
+import 'package:pve_flutter_frontend/states/proxmox_form_field_state.dart';
class PveGuestIdSelector extends StatelessWidget {
+ final String labelText;
+
+ PveGuestIdSelector(
+ {Key key,
+ this.labelText,})
+ : super(key: key);
+
@override
Widget build(BuildContext context) {
final _pveGuestIdSelectorBloc =
Provider.of<PveGuestIdSelectorBloc>(context);
-
- return StreamBuilder<PveGuestIdSelectorState>(
+ return StreamBuilder<PveFormFieldState>(
stream: _pveGuestIdSelectorBloc.state,
+ initialData: _pveGuestIdSelectorBloc.state.value,
builder: (context, snapshot) {
- print("build");
- if (snapshot.hasData) {
- final state = snapshot.data;
- return TextFormField(
- decoration:
- InputDecoration(labelText: 'VM ID', errorText: state.error),
- initialValue: state.id,
- keyboardType: TextInputType.number,
- inputFormatters: [WhitelistingTextInputFormatter.digitsOnly],
- onChanged: (text) {
- _pveGuestIdSelectorBloc.events.add(ValidateInput(text));
- },
- );
- }
- return Container();
+ final state = snapshot.data;
+
+ return TextFormField(
+ // make sure a new internal state is created if the
+ // first build has no data
+ key: state.value != null ? null : ValueKey(1),
+ decoration: InputDecoration(labelText: labelText, helperText: ' '),
+ initialValue: state?.value,
+ keyboardType: TextInputType.number,
+ inputFormatters: [WhitelistingTextInputFormatter.digitsOnly],
+ autovalidate: true,
+ onChanged: (text) {
+ _pveGuestIdSelectorBloc.events.add(OnChanged(text));
+ },
+ validator: (_) {
+ return state?.errorText;
+ },
+ );
});
}
}