ui: Migrate [AddContactPage] to Bloc
This commit is contained in:
66
lib/ui/bloc/addcontact_bloc.dart
Normal file
66
lib/ui/bloc/addcontact_bloc.dart
Normal file
@@ -0,0 +1,66 @@
|
||||
import "package:moxxyv2/shared/commands.dart";
|
||||
import "package:moxxyv2/shared/events.dart";
|
||||
import "package:moxxyv2/shared/helpers.dart";
|
||||
import "package:moxxyv2/shared/backgroundsender.dart";
|
||||
import "package:moxxyv2/ui/bloc/conversations_bloc.dart";
|
||||
import "package:moxxyv2/ui/bloc/conversation_bloc.dart";
|
||||
|
||||
import "package:get_it/get_it.dart";
|
||||
import "package:bloc/bloc.dart";
|
||||
import "package:freezed_annotation/freezed_annotation.dart";
|
||||
|
||||
part "addcontact_state.dart";
|
||||
part "addcontact_event.dart";
|
||||
part "addcontact_bloc.freezed.dart";
|
||||
|
||||
class AddContactBloc extends Bloc<AddContactEvent, AddContactState> {
|
||||
AddContactBloc() : super(AddContactState()) {
|
||||
on<AddedContactEvent>(_onContactAdded);
|
||||
on<JidChangedEvent>(_onJidChanged);
|
||||
}
|
||||
|
||||
Future<void> _onContactAdded(AddedContactEvent event, Emitter<AddContactState> emit) async {
|
||||
// TODO: Remove once we can disable the custom buttom
|
||||
if (state.working) return;
|
||||
|
||||
final validation = validateJidString(state.jid);
|
||||
if (validation != null) {
|
||||
emit(state.copyWith(jidError: validation));
|
||||
return;
|
||||
}
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
working: true,
|
||||
jidError: null
|
||||
)
|
||||
);
|
||||
|
||||
final result = await GetIt.I.get<BackgroundServiceDataSender>().sendData(
|
||||
AddContactCommand(
|
||||
jid: state.jid
|
||||
)
|
||||
) as AddContactResultEvent;
|
||||
|
||||
if (result.conversation != null) {
|
||||
if (result.added) {
|
||||
GetIt.I.get<ConversationsBloc>().add(ConversationsAddedEvent(result.conversation!));
|
||||
} else {
|
||||
GetIt.I.get<ConversationsBloc>().add(ConversationsUpdatedEvent(result.conversation!));
|
||||
}
|
||||
}
|
||||
|
||||
GetIt.I.get<ConversationBloc>().add(
|
||||
RequestedConversationEvent(
|
||||
result.conversation!.jid,
|
||||
result.conversation!.title,
|
||||
result.conversation!.avatarUrl,
|
||||
removeUntilConversations: true
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onJidChanged(JidChangedEvent event, Emitter<AddContactState> emit) async {
|
||||
emit(state.copyWith(jid: event.jid));
|
||||
}
|
||||
}
|
||||
13
lib/ui/bloc/addcontact_event.dart
Normal file
13
lib/ui/bloc/addcontact_event.dart
Normal file
@@ -0,0 +1,13 @@
|
||||
part of "addcontact_bloc.dart";
|
||||
|
||||
abstract class AddContactEvent {}
|
||||
|
||||
/// Triggered when a new contact has been added by the UI
|
||||
class AddedContactEvent extends AddContactEvent {}
|
||||
|
||||
/// Triggered by the UI when the JID input field is changed
|
||||
class JidChangedEvent extends AddContactEvent {
|
||||
final String jid;
|
||||
|
||||
JidChangedEvent(this.jid);
|
||||
}
|
||||
10
lib/ui/bloc/addcontact_state.dart
Normal file
10
lib/ui/bloc/addcontact_state.dart
Normal file
@@ -0,0 +1,10 @@
|
||||
part of "addcontact_bloc.dart";
|
||||
|
||||
@freezed
|
||||
class AddContactState with _$AddContactState {
|
||||
factory AddContactState({
|
||||
@Default("") String jid,
|
||||
@Default(null) String? jidError,
|
||||
@Default(false) bool working
|
||||
}) = _AddContactState;
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import "package:moxxyv2/ui/bloc/conversations_bloc.dart";
|
||||
import "package:get_it/get_it.dart";
|
||||
import "package:bloc/bloc.dart";
|
||||
import "package:freezed_annotation/freezed_annotation.dart";
|
||||
import "package:flutter/widgets.dart";
|
||||
|
||||
part "conversation_state.dart";
|
||||
part "conversation_event.dart";
|
||||
@@ -47,11 +48,18 @@ class ConversationBloc extends Bloc<ConversationEvent, ConversationState> {
|
||||
)
|
||||
);
|
||||
|
||||
GetIt.I.get<NavigationBloc>().add(
|
||||
final navEvent = event.removeUntilConversations ? (
|
||||
PushedNamedAndRemoveUntilEvent(
|
||||
const NavigationDestination(conversationRoute),
|
||||
ModalRoute.withName(conversationsRoute)
|
||||
)
|
||||
) : (
|
||||
PushedNamedEvent(
|
||||
const NavigationDestination(conversationRoute)
|
||||
)
|
||||
);
|
||||
|
||||
GetIt.I.get<NavigationBloc>().add(navEvent);
|
||||
|
||||
final result = await GetIt.I.get<BackgroundServiceDataSender>().sendData(
|
||||
GetMessagesForJidCommand(
|
||||
|
||||
@@ -28,8 +28,16 @@ class RequestedConversationEvent extends ConversationEvent {
|
||||
final String jid;
|
||||
final String title;
|
||||
final String avatarUrl;
|
||||
final bool removeUntilConversations;
|
||||
|
||||
RequestedConversationEvent(this.jid, this.title, this.avatarUrl);
|
||||
RequestedConversationEvent(
|
||||
this.jid,
|
||||
this.title,
|
||||
this.avatarUrl,
|
||||
{
|
||||
this.removeUntilConversations = false
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/// Triggered by the UI when a message is quoted
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import "package:moxxyv2/shared/events.dart";
|
||||
import "package:moxxyv2/shared/backgroundsender.dart";
|
||||
import "package:moxxyv2/shared/models/conversation.dart";
|
||||
|
||||
import "package:bloc/bloc.dart";
|
||||
|
||||
@@ -14,20 +14,6 @@ part "login_state.dart";
|
||||
part "login_event.dart";
|
||||
part "login_bloc.freezed.dart";
|
||||
|
||||
/// Returns an error string if [jid] is not a valid JID. Returns null if everything
|
||||
/// appears okay.
|
||||
String? _validateJid(String jid) {
|
||||
switch (validateJid(jid)) {
|
||||
case JidFormatError.empty: return "XMPP-Address cannot be empty";
|
||||
case JidFormatError.noSeparator:
|
||||
case JidFormatError.tooManySeparators: return "XMPP-Address must contain exactly one @";
|
||||
// TODO: Find a better text
|
||||
case JidFormatError.noDomain: return "A domain must follow the @";
|
||||
case JidFormatError.noLocalpart: return "Your username must preceed the @";
|
||||
case JidFormatError.none: return null;
|
||||
}
|
||||
}
|
||||
|
||||
class LoginBloc extends Bloc<LoginEvent, LoginState> {
|
||||
LoginBloc() : super(LoginState()) {
|
||||
on<LoginJidChangedEvent>(_onJidChanged);
|
||||
@@ -49,7 +35,7 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> {
|
||||
}
|
||||
|
||||
Future<void> _onSubmitted(LoginSubmittedEvent event, Emitter<LoginState> emit) async {
|
||||
final jidValidity = _validateJid(state.jid);
|
||||
final jidValidity = validateJidString(state.jid);
|
||||
if (jidValidity != null) {
|
||||
return emit(
|
||||
state.copyWith(
|
||||
|
||||
@@ -4,14 +4,12 @@ import "package:moxxyv2/shared/helpers.dart";
|
||||
import "package:moxxyv2/shared/models/roster.dart";
|
||||
import "package:moxxyv2/shared/models/conversation.dart";
|
||||
import "package:moxxyv2/shared/backgroundsender.dart";
|
||||
import "package:moxxyv2/ui/constants.dart";
|
||||
import "package:moxxyv2/ui/bloc/conversations_bloc.dart";
|
||||
import "package:moxxyv2/ui/bloc/navigation_bloc.dart";
|
||||
import "package:moxxyv2/ui/bloc/conversation_bloc.dart";
|
||||
|
||||
import "package:bloc/bloc.dart";
|
||||
import "package:freezed_annotation/freezed_annotation.dart";
|
||||
import "package:get_it/get_it.dart";
|
||||
import "package:flutter/widgets.dart";
|
||||
|
||||
part "newconversation_state.dart";
|
||||
part "newconversation_event.dart";
|
||||
@@ -38,14 +36,12 @@ class NewConversationBloc extends Bloc<NewConversationEvent, NewConversationStat
|
||||
|
||||
// Guard against an unneccessary roundtrip
|
||||
if (listContains(conversations.state.conversations, (Conversation c) => c.jid == event.jid)) {
|
||||
// TODO: Use the [ConversationBloc]
|
||||
GetIt.I.get<NavigationBloc>().add(
|
||||
PushedNamedAndRemoveUntilEvent(
|
||||
NavigationDestination(
|
||||
conversationRoute,
|
||||
//arguments: ConversationPageArguments(event.jid)
|
||||
),
|
||||
ModalRoute.withName(conversationsRoute)
|
||||
GetIt.I.get<ConversationBloc>().add(
|
||||
RequestedConversationEvent(
|
||||
event.jid,
|
||||
event.title,
|
||||
event.avatarUrl,
|
||||
removeUntilConversations: true
|
||||
)
|
||||
);
|
||||
return;
|
||||
@@ -68,20 +64,17 @@ class NewConversationBloc extends Bloc<NewConversationEvent, NewConversationStat
|
||||
conversations.add(ConversationsAddedEvent(result.conversation));
|
||||
}
|
||||
|
||||
// TODO: Use the [ConversationBloc]
|
||||
GetIt.I.get<NavigationBloc>().add(
|
||||
PushedNamedAndRemoveUntilEvent(
|
||||
NavigationDestination(
|
||||
conversationRoute,
|
||||
//arguments: ConversationPageArguments(event.jid)
|
||||
),
|
||||
ModalRoute.withName(conversationsRoute)
|
||||
GetIt.I.get<ConversationBloc>().add(
|
||||
RequestedConversationEvent(
|
||||
event.jid,
|
||||
event.title,
|
||||
event.avatarUrl,
|
||||
removeUntilConversations: true
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onRosterItemRemoved(NewConversationRosterItemRemovedEvent event, Emitter<NewConversationState> emit) async {
|
||||
// TODO
|
||||
return emit(
|
||||
state.copyWith(
|
||||
roster: state.roster.where(
|
||||
|
||||
Reference in New Issue
Block a user