refactor: Simplify login UX
parent
f17b09f56c
commit
dec588d0c0
@ -1,109 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:flutter_typeahead/flutter_typeahead.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/config/themes.dart';
|
||||
import 'package:fluffychat/pages/homeserver_picker/public_homeserver.dart';
|
||||
import 'package:fluffychat/utils/localized_exception_extension.dart';
|
||||
import 'homeserver_bottom_sheet.dart';
|
||||
import 'homeserver_picker.dart';
|
||||
|
||||
class HomeserverAppBar extends StatelessWidget {
|
||||
final HomeserverPickerController controller;
|
||||
|
||||
const HomeserverAppBar({super.key, required this.controller});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
|
||||
return TypeAheadField<PublicHomeserver>(
|
||||
decorationBuilder: (context, child) => ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxHeight: 256),
|
||||
child: Material(
|
||||
borderRadius: BorderRadius.circular(AppConfig.borderRadius),
|
||||
elevation: theme.appBarTheme.scrolledUnderElevation ?? 4,
|
||||
shadowColor: theme.appBarTheme.shadowColor ?? Colors.black,
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
emptyBuilder: (context) => ListTile(
|
||||
leading: const Icon(Icons.search_outlined),
|
||||
title: Text(L10n.of(context)!.nothingFound),
|
||||
),
|
||||
loadingBuilder: (context) => ListTile(
|
||||
leading: const CircularProgressIndicator.adaptive(strokeWidth: 2),
|
||||
title: Text(L10n.of(context)!.loadingPleaseWait),
|
||||
),
|
||||
errorBuilder: (context, error) => ListTile(
|
||||
leading: const Icon(Icons.error_outlined),
|
||||
title: Text(
|
||||
error.toLocalizedString(context),
|
||||
),
|
||||
),
|
||||
itemBuilder: (context, homeserver) => ListTile(
|
||||
title: Text(homeserver.name),
|
||||
subtitle: homeserver.description == null
|
||||
? null
|
||||
: Text(homeserver.description ?? ''),
|
||||
trailing: IconButton(
|
||||
icon: const Icon(Icons.info_outlined),
|
||||
onPressed: () => showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (_) => HomeserverBottomSheet(
|
||||
homeserver: homeserver,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
suggestionsCallback: (pattern) async {
|
||||
pattern = pattern.toLowerCase().trim();
|
||||
final homeservers = await controller.loadHomeserverList();
|
||||
final matches = homeservers
|
||||
.where(
|
||||
(homeserver) =>
|
||||
homeserver.name.toLowerCase().contains(pattern) ||
|
||||
(homeserver.description?.toLowerCase().contains(pattern) ??
|
||||
false),
|
||||
)
|
||||
.toList();
|
||||
if (pattern.contains('.') &&
|
||||
pattern.split('.').any((part) => part.isNotEmpty) &&
|
||||
!matches.any((homeserver) => homeserver.name == pattern)) {
|
||||
matches.add(PublicHomeserver(name: pattern));
|
||||
}
|
||||
return matches;
|
||||
},
|
||||
onSelected: (suggestion) {
|
||||
controller.homeserverController.text = suggestion.name;
|
||||
controller.checkHomeserverAction();
|
||||
},
|
||||
controller: controller.homeserverController,
|
||||
builder: (context, textEditingController, focusNode) => TextField(
|
||||
enabled: !controller.isLoggingIn,
|
||||
controller: textEditingController,
|
||||
focusNode: focusNode,
|
||||
decoration: InputDecoration(
|
||||
prefixIcon: Navigator.of(context).canPop()
|
||||
? IconButton(
|
||||
onPressed: Navigator.of(context).pop,
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
)
|
||||
: null,
|
||||
fillColor: FluffyThemes.isColumnMode(context)
|
||||
? theme.colorScheme.surface
|
||||
// ignore: deprecated_member_use
|
||||
: theme.colorScheme.surfaceVariant,
|
||||
prefixText: '${L10n.of(context)!.homeserver}: ',
|
||||
hintText: L10n.of(context)!.enterYourHomeserver,
|
||||
suffixIcon: const Icon(Icons.search),
|
||||
),
|
||||
textInputAction: TextInputAction.search,
|
||||
onSubmitted: controller.checkHomeserverAction,
|
||||
autocorrect: false,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
|
||||
import 'package:fluffychat/pages/homeserver_picker/public_homeserver.dart';
|
||||
|
||||
class HomeserverBottomSheet extends StatelessWidget {
|
||||
final PublicHomeserver homeserver;
|
||||
const HomeserverBottomSheet({required this.homeserver, super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final description = homeserver.description;
|
||||
final registration = homeserver.regLink;
|
||||
final jurisdiction = homeserver.staffJur;
|
||||
final homeserverSoftware = homeserver.software;
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(homeserver.name),
|
||||
),
|
||||
body: ListView(
|
||||
children: [
|
||||
if (description != null && description.isNotEmpty)
|
||||
ListTile(
|
||||
leading: const Icon(Icons.info_outlined),
|
||||
title: Text(description),
|
||||
),
|
||||
if (jurisdiction != null && jurisdiction.isNotEmpty)
|
||||
ListTile(
|
||||
leading: const Icon(Icons.location_city_outlined),
|
||||
title: Text(jurisdiction),
|
||||
),
|
||||
if (homeserverSoftware != null && homeserverSoftware.isNotEmpty)
|
||||
ListTile(
|
||||
leading: const Icon(Icons.domain_outlined),
|
||||
title: Text(homeserverSoftware),
|
||||
),
|
||||
ListTile(
|
||||
onTap: () => launchUrlString(homeserver.name),
|
||||
leading: const Icon(Icons.link_outlined),
|
||||
title: Text(homeserver.name),
|
||||
),
|
||||
if (registration != null)
|
||||
ListTile(
|
||||
onTap: () => launchUrlString(registration),
|
||||
leading: const Icon(Icons.person_add_outlined),
|
||||
title: Text(registration),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
class PublicHomeserver {
|
||||
final String name;
|
||||
final String? clientDomain;
|
||||
final String? isp;
|
||||
final String? staffJur;
|
||||
final bool? usingVanillaReg;
|
||||
final String? description;
|
||||
final String? regMethod;
|
||||
final String? regLink;
|
||||
final String? software;
|
||||
final String? version;
|
||||
final bool? captcha;
|
||||
final bool? email;
|
||||
final List<String>? languages;
|
||||
final List<Object>? features;
|
||||
final int? onlineStatus;
|
||||
final String? serverDomain;
|
||||
final int? verStatus;
|
||||
final int? roomDirectory;
|
||||
final bool? slidingSync;
|
||||
final bool? ipv6;
|
||||
|
||||
const PublicHomeserver({
|
||||
required this.name,
|
||||
this.clientDomain,
|
||||
this.isp,
|
||||
this.staffJur,
|
||||
this.usingVanillaReg,
|
||||
this.description,
|
||||
this.regMethod,
|
||||
this.regLink,
|
||||
this.software,
|
||||
this.version,
|
||||
this.captcha,
|
||||
this.email,
|
||||
this.languages,
|
||||
this.features,
|
||||
this.onlineStatus,
|
||||
this.serverDomain,
|
||||
this.verStatus,
|
||||
this.roomDirectory,
|
||||
this.slidingSync,
|
||||
this.ipv6,
|
||||
});
|
||||
|
||||
factory PublicHomeserver.fromJson(Map<String, dynamic> json) =>
|
||||
PublicHomeserver(
|
||||
name: json['name'],
|
||||
clientDomain: json['client_domain'],
|
||||
isp: json['isp'],
|
||||
staffJur: json['staff_jur'],
|
||||
usingVanillaReg: json['using_vanilla_reg'],
|
||||
description: json['description'],
|
||||
regMethod: json['reg_method'],
|
||||
regLink: json['reg_link'],
|
||||
software: json['software'],
|
||||
version: json['version'],
|
||||
captcha: json['captcha'],
|
||||
email: json['email'],
|
||||
languages: json['languages'] == null
|
||||
? null
|
||||
: List<String>.from(json['languages']),
|
||||
features: json['features'] == null
|
||||
? null
|
||||
: List<Object>.from(json['features']),
|
||||
onlineStatus: json['online_status'],
|
||||
serverDomain: json['server_domain'],
|
||||
verStatus: json['ver_status'],
|
||||
roomDirectory: json['room_directory'],
|
||||
slidingSync: json['sliding_sync'],
|
||||
ipv6: json['ipv6'],
|
||||
);
|
||||
}
|
Loading…
Reference in New Issue