ui: Migrate [AddContactPage] to Bloc
This commit is contained in:
		
							parent
							
								
									7a999d40d8
								
							
						
					
					
						commit
						489ef364c1
					
				@ -139,6 +139,19 @@ files:
 | 
			
		||||
          removed:
 | 
			
		||||
            type: List<String>
 | 
			
		||||
            default: "[]"
 | 
			
		||||
      # Triggered by the service in response to an [AddContactCommand].
 | 
			
		||||
      - name: AddContactResultEvent
 | 
			
		||||
        extends:
 | 
			
		||||
          - BackgroundEvent
 | 
			
		||||
        implements:
 | 
			
		||||
          - JsonImplementation
 | 
			
		||||
        attributes:
 | 
			
		||||
          conversation:
 | 
			
		||||
            type: Conversation?
 | 
			
		||||
            deserialise: true
 | 
			
		||||
          # Indicate if the conversation is new (true) or modified (false).
 | 
			
		||||
          # Does not mean anything unless conversation != null.
 | 
			
		||||
          added: bool
 | 
			
		||||
    generate_builder: true
 | 
			
		||||
    builder_name: "Event"
 | 
			
		||||
    builder_baseclass: "BackgroundEvent"
 | 
			
		||||
@ -229,6 +242,13 @@ files:
 | 
			
		||||
          preferences:
 | 
			
		||||
            type: PreferencesState
 | 
			
		||||
            deserialise: true
 | 
			
		||||
      - name: AddContactCommand
 | 
			
		||||
        extends:
 | 
			
		||||
          - BackgroundCommand
 | 
			
		||||
        implements:
 | 
			
		||||
          - JsonImplementation
 | 
			
		||||
        attributes:
 | 
			
		||||
          jid: String
 | 
			
		||||
    generate_builder: true
 | 
			
		||||
    # get${builder_Name}FromJson
 | 
			
		||||
    builder_name: "Command"
 | 
			
		||||
 | 
			
		||||
@ -4,8 +4,8 @@ import "package:moxxyv2/ui/constants.dart";
 | 
			
		||||
import "package:moxxyv2/ui/pages/register/register.dart";
 | 
			
		||||
import "package:moxxyv2/ui/pages/postregister/postregister.dart";
 | 
			
		||||
import "package:moxxyv2/ui/pages/sendfiles.dart";
 | 
			
		||||
import "package:moxxyv2/ui/pages/addcontact/addcontact.dart";
 | 
			
		||||
*/
 | 
			
		||||
import "package:moxxyv2/ui/pages/addcontact/addcontact.dart";
 | 
			
		||||
import "package:moxxyv2/ui/pages/settings/debugging.dart";
 | 
			
		||||
import "package:moxxyv2/ui/pages/settings/privacy.dart";
 | 
			
		||||
import "package:moxxyv2/ui/pages/settings/network.dart";
 | 
			
		||||
@ -29,6 +29,7 @@ import "package:moxxyv2/ui/bloc/conversation_bloc.dart";
 | 
			
		||||
import "package:moxxyv2/ui/bloc/blocklist_bloc.dart";
 | 
			
		||||
import "package:moxxyv2/ui/bloc/profile_bloc.dart";
 | 
			
		||||
import "package:moxxyv2/ui/bloc/preferences_bloc.dart";
 | 
			
		||||
import "package:moxxyv2/ui/bloc/addcontact_bloc.dart";
 | 
			
		||||
import "package:moxxyv2/ui/service/download.dart";
 | 
			
		||||
import "package:moxxyv2/service/service.dart";
 | 
			
		||||
import "package:moxxyv2/shared/commands.dart";
 | 
			
		||||
@ -62,6 +63,7 @@ void setupBlocs(GlobalKey<NavigatorState> navKey) {
 | 
			
		||||
  GetIt.I.registerSingleton<BlocklistBloc>(BlocklistBloc());
 | 
			
		||||
  GetIt.I.registerSingleton<ProfileBloc>(ProfileBloc());
 | 
			
		||||
  GetIt.I.registerSingleton<PreferencesBloc>(PreferencesBloc());
 | 
			
		||||
  GetIt.I.registerSingleton<AddContactBloc>(AddContactBloc());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO: Replace all Column(children: [ Padding(), Padding, ...]) with a
 | 
			
		||||
@ -104,6 +106,9 @@ void main() async {
 | 
			
		||||
        ),
 | 
			
		||||
        BlocProvider<PreferencesBloc>(
 | 
			
		||||
          create: (_) => GetIt.I.get<PreferencesBloc>()
 | 
			
		||||
        ),
 | 
			
		||||
        BlocProvider<AddContactBloc>(
 | 
			
		||||
          create: (_) => GetIt.I.get<AddContactBloc>()
 | 
			
		||||
        )
 | 
			
		||||
      ],
 | 
			
		||||
      child: MyApp(navKey)
 | 
			
		||||
@ -235,11 +240,11 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
 | 
			
		||||
        networkRoute: (context) => const NetworkPage(),
 | 
			
		||||
        privacyRoute: (context) => const PrivacyPage(),
 | 
			
		||||
        debuggingRoute: (context) => DebuggingPage(),
 | 
			
		||||
        addContactRoute: (context) => AddContactPage(),
 | 
			
		||||
        /*
 | 
			
		||||
        registrationRoute: (context) => RegistrationPage(),
 | 
			
		||||
        postRegistrationRoute: (context) => const PostRegistrationPage(),
 | 
			
		||||
        sendFilesRoute: (context) => SendFilesPage(),
 | 
			
		||||
        addContactRoute: (context) => AddContactPage(),
 | 
			
		||||
        */
 | 
			
		||||
      },
 | 
			
		||||
      home: Splashscreen()
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,7 @@ import "package:moxxyv2/service/preferences.dart";
 | 
			
		||||
import "package:moxxyv2/service/roster.dart";
 | 
			
		||||
import "package:moxxyv2/service/database.dart";
 | 
			
		||||
import "package:moxxyv2/service/blocking.dart";
 | 
			
		||||
import "package:moxxyv2/service/avatars.dart";
 | 
			
		||||
import "package:moxxyv2/xmpp/connection.dart";
 | 
			
		||||
import "package:moxxyv2/xmpp/settings.dart";
 | 
			
		||||
import "package:moxxyv2/xmpp/jid.dart";
 | 
			
		||||
@ -207,3 +208,47 @@ Future<void> performSetPreferences(BaseEvent c, { dynamic extra }) async {
 | 
			
		||||
  final command = c as SetPreferencesCommand;
 | 
			
		||||
  GetIt.I.get<PreferencesService>().modifyPreferences((_) => command.preferences);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Future<void> performAddContact(BaseEvent c, { dynamic extra }) async {
 | 
			
		||||
  final command = c as AddContactCommand;
 | 
			
		||||
  final id = extra as String;
 | 
			
		||||
 | 
			
		||||
  final jid = command.jid;
 | 
			
		||||
  final roster = GetIt.I.get<RosterService>();
 | 
			
		||||
  if (await roster.isInRoster(jid)) {
 | 
			
		||||
    sendEvent(AddContactResultEvent(conversation: null, added: false), id: id);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  final db = GetIt.I.get<DatabaseService>();
 | 
			
		||||
  final conversation = await db.getConversationByJid(jid);
 | 
			
		||||
  if (conversation != null) {
 | 
			
		||||
    final c = await db.updateConversation(id: conversation.id, open: true);
 | 
			
		||||
 | 
			
		||||
    sendEvent(
 | 
			
		||||
      AddContactResultEvent(conversation: c, added: false),
 | 
			
		||||
      id: id
 | 
			
		||||
    );
 | 
			
		||||
  } else {            
 | 
			
		||||
    final c = await db.addConversationFromData(
 | 
			
		||||
      jid.split("@")[0],
 | 
			
		||||
      "",
 | 
			
		||||
      "",
 | 
			
		||||
      jid,
 | 
			
		||||
      0,
 | 
			
		||||
      -1,
 | 
			
		||||
      [],
 | 
			
		||||
      true
 | 
			
		||||
    );
 | 
			
		||||
    sendEvent(
 | 
			
		||||
      AddContactResultEvent(conversation: c, added: true),
 | 
			
		||||
      id: id
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  roster.addToRosterWrapper("", jid, jid.split("@")[0]);
 | 
			
		||||
  
 | 
			
		||||
  // Try to figure out an avatar
 | 
			
		||||
  await GetIt.I.get<AvatarService>().subscribeJid(jid);
 | 
			
		||||
  GetIt.I.get<AvatarService>().fetchAndUpdateAvatarForJid(jid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -106,6 +106,20 @@ JidFormatError validateJid(String jid) {
 | 
			
		||||
  return JidFormatError.none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Returns an error string if [jid] is not a valid JID. Returns null if everything
 | 
			
		||||
/// appears okay.
 | 
			
		||||
String? validateJidString(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;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Returns the first element in [items] which is non null.
 | 
			
		||||
/// Returns null if they all are null.
 | 
			
		||||
T? firstNotNull<T>(List<T?> items) {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										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(
 | 
			
		||||
 | 
			
		||||
@ -1,52 +1,25 @@
 | 
			
		||||
/*
 | 
			
		||||
import "package:moxxyv2/ui/constants.dart";
 | 
			
		||||
import "package:moxxyv2/ui/helpers.dart";
 | 
			
		||||
import "package:moxxyv2/ui/widgets/topbar.dart";
 | 
			
		||||
import "package:moxxyv2/ui/widgets/textfield.dart";
 | 
			
		||||
import "package:moxxyv2/ui/widgets/button.dart";
 | 
			
		||||
import "package:moxxyv2/ui/constants.dart";
 | 
			
		||||
import "package:moxxyv2/ui/helpers.dart";
 | 
			
		||||
import "package:moxxyv2/ui/redux/state.dart";
 | 
			
		||||
import "package:moxxyv2/ui/redux/addcontact/actions.dart";
 | 
			
		||||
import "package:moxxyv2/ui/bloc/addcontact_bloc.dart";
 | 
			
		||||
 | 
			
		||||
import "package:flutter/material.dart";
 | 
			
		||||
import "package:flutter_redux/flutter_redux.dart";
 | 
			
		||||
import "package:flutter_bloc/flutter_bloc.dart";
 | 
			
		||||
 | 
			
		||||
class _AddContactPageViewModel {
 | 
			
		||||
  final bool doingWork;
 | 
			
		||||
  final String? errorText;
 | 
			
		||||
  final void Function(String jid) addContact;
 | 
			
		||||
  final void Function() resetErrors;
 | 
			
		||||
 | 
			
		||||
  const _AddContactPageViewModel({ required this.addContact, required this.doingWork, required this.resetErrors, this.errorText });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO: Reset the errorText using WillPopScope
 | 
			
		||||
class AddContactPage extends StatelessWidget {
 | 
			
		||||
  final TextEditingController _controller;
 | 
			
		||||
 | 
			
		||||
  AddContactPage({ Key? key }) : _controller = TextEditingController(), super(key: key);
 | 
			
		||||
  
 | 
			
		||||
  void _addToRoster(BuildContext context, _AddContactPageViewModel viewModel) {
 | 
			
		||||
    if (_controller.text.isEmpty) return;
 | 
			
		||||
 | 
			
		||||
    viewModel.resetErrors();
 | 
			
		||||
    viewModel.addContact(_controller.text);
 | 
			
		||||
  }
 | 
			
		||||
  const AddContactPage({ Key? key }) : super(key: key);
 | 
			
		||||
  
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    return StoreConnector<MoxxyState, _AddContactPageViewModel>(
 | 
			
		||||
      converter: (store) => _AddContactPageViewModel(
 | 
			
		||||
        doingWork: store.state.globalState.doingWork,
 | 
			
		||||
        errorText: store.state.addContactErrorText,
 | 
			
		||||
        addContact: (jid) => store.dispatch(AddContactAction(jid: jid)),
 | 
			
		||||
        resetErrors: () => store.dispatch(AddContactSetErrorLogin())
 | 
			
		||||
      ),
 | 
			
		||||
      builder: (context, viewModel) => Scaffold(
 | 
			
		||||
    return BlocBuilder<AddContactBloc, AddContactState>(
 | 
			
		||||
      builder: (context, state) => Scaffold(
 | 
			
		||||
        appBar: BorderlessTopbar.simple(title: "Add new contact"),
 | 
			
		||||
        body: Column(
 | 
			
		||||
          children: [
 | 
			
		||||
            Visibility(
 | 
			
		||||
              visible: viewModel.doingWork,
 | 
			
		||||
              visible: state.working,
 | 
			
		||||
              child: const LinearProgressIndicator(value: null)
 | 
			
		||||
            ),
 | 
			
		||||
 | 
			
		||||
@ -54,11 +27,14 @@ class AddContactPage extends StatelessWidget {
 | 
			
		||||
              padding: const EdgeInsets.symmetric(horizontal: paddingVeryLarge).add(const EdgeInsets.only(top: 8.0)),
 | 
			
		||||
              child: CustomTextField(
 | 
			
		||||
                maxLines: 1,
 | 
			
		||||
                controller: _controller,
 | 
			
		||||
                labelText: "XMPP-Address",
 | 
			
		||||
                onChanged: (value) => context.read<AddContactBloc>().add(
 | 
			
		||||
                  JidChangedEvent(value)
 | 
			
		||||
                ),
 | 
			
		||||
                enabled: !state.working,
 | 
			
		||||
                cornerRadius: textfieldRadiusRegular,
 | 
			
		||||
                contentPadding: const EdgeInsets.only(top: 4.0, bottom: 4.0, left: 8.0, right: 8.0),
 | 
			
		||||
                errorText: viewModel.errorText,
 | 
			
		||||
                errorText: state.jidError,
 | 
			
		||||
                suffixIcon: IconButton(
 | 
			
		||||
                  icon: const Icon(Icons.qr_code),
 | 
			
		||||
                  onPressed: () {
 | 
			
		||||
@ -84,7 +60,7 @@ class AddContactPage extends StatelessWidget {
 | 
			
		||||
                      color: Colors.purple,
 | 
			
		||||
                      child: const Text("Add to contacts"),
 | 
			
		||||
                      cornerRadius: 32.0,
 | 
			
		||||
                      onTap: () => _addToRoster(context, viewModel)
 | 
			
		||||
                      onTap: () => context.read<AddContactBloc>().add(AddedContactEvent())
 | 
			
		||||
                    )
 | 
			
		||||
                  )
 | 
			
		||||
                ]
 | 
			
		||||
@ -96,4 +72,3 @@ class AddContactPage extends StatelessWidget {
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user