mirror of
https://gitlab.com/famedly/fluffychat.git
synced 2025-02-17 06:20:44 +01:00
fix: onboarding UX
- add missing label to progress indicator - add option to enable locale based homeservers (disabled by default) Signed-off-by: TheOneWithTheBraid <the-one@with-the-braid.cf>
This commit is contained in:
parent
014c1574ee
commit
b4cc484f38
@ -376,6 +376,7 @@
|
||||
"type": "text",
|
||||
"placeholders": {}
|
||||
},
|
||||
"benchmarkingHomeserver": "Finding the fastest instances around you...",
|
||||
"changeTheme": "Change your style",
|
||||
"@changeTheme": {
|
||||
"type": "text",
|
||||
|
@ -6,5 +6,6 @@
|
||||
"privacy_url": "https://fluffychat.im/en/privacy.html",
|
||||
"render_html": false,
|
||||
"hide_redacted_events": false,
|
||||
"hide_unknown_events": false
|
||||
"hide_unknown_events": false,
|
||||
"use_location_based_homeserver": false
|
||||
}
|
@ -4,10 +4,13 @@ import 'package:matrix/matrix.dart';
|
||||
|
||||
abstract class AppConfig {
|
||||
static String _applicationName = 'FluffyChat';
|
||||
|
||||
static String get applicationName => _applicationName;
|
||||
static String? _applicationWelcomeMessage;
|
||||
|
||||
static String? get applicationWelcomeMessage => _applicationWelcomeMessage;
|
||||
static String _defaultHomeserver = 'matrix.org';
|
||||
|
||||
static String get defaultHomeserver => _defaultHomeserver;
|
||||
static double bubbleSizeFactor = 1;
|
||||
static double fontSizeFactor = 1;
|
||||
@ -21,12 +24,14 @@ abstract class AppConfig {
|
||||
static const Color secondaryColor = Color(0xFF41a2bc);
|
||||
static String _privacyUrl =
|
||||
'https://gitlab.com/famedly/fluffychat/-/blob/main/PRIVACY.md';
|
||||
|
||||
static String get privacyUrl => _privacyUrl;
|
||||
static const String enablePushTutorial =
|
||||
'https://www.reddit.com/r/fluffychat/comments/qn6liu/enable_push_notifications_without_google_services/';
|
||||
static const String appId = 'im.fluffychat.FluffyChat';
|
||||
static const String appOpenUrlScheme = 'im.fluffychat';
|
||||
static String _webBaseUrl = 'https://fluffychat.im/web';
|
||||
|
||||
static String get webBaseUrl => _webBaseUrl;
|
||||
static const String sourceCodeUrl = 'https://gitlab.com/famedly/fluffychat';
|
||||
static const String supportUrl =
|
||||
@ -60,6 +65,7 @@ abstract class AppConfig {
|
||||
'https://github.com/googlefonts/noto-emoji/';
|
||||
static const double borderRadius = 16.0;
|
||||
static const double columnWidth = 360.0;
|
||||
static bool useLocaleBasedHomeserver = false;
|
||||
|
||||
static void loadFromJson(Map<String, dynamic> json) {
|
||||
if (json['chat_color'] != null) {
|
||||
@ -95,5 +101,8 @@ abstract class AppConfig {
|
||||
if (json['hide_unknown_events'] is bool) {
|
||||
hideUnknownEvents = json['hide_unknown_events'];
|
||||
}
|
||||
if (json['use_location_based_homeserver'] is bool) {
|
||||
useLocaleBasedHomeserver = json['use_location_based_homeserver'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
27
lib/config/homeserver_locale.dart
Normal file
27
lib/config/homeserver_locale.dart
Normal file
@ -0,0 +1,27 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
part 'homeserver_locale_map.dart';
|
||||
|
||||
class HomeserverLocale {
|
||||
final Locale locale;
|
||||
|
||||
const HomeserverLocale(this.locale);
|
||||
|
||||
String? choose() {
|
||||
if (locale.countryCode == null) return null;
|
||||
final country = locale.countryCode!.toLowerCase();
|
||||
try {
|
||||
if (_homeserverByLocale.containsKey(country)) {
|
||||
return _homeserverByLocale[country];
|
||||
} else if (_countryCodeContinent.containsKey(country)) {
|
||||
final continent = _countryCodeContinent[country];
|
||||
return _homeserverByContinent[continent];
|
||||
}
|
||||
} catch (e) {
|
||||
Logs().w('Error matching country code $country');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
281
lib/config/homeserver_locale_map.dart
Normal file
281
lib/config/homeserver_locale_map.dart
Normal file
@ -0,0 +1,281 @@
|
||||
part of 'homeserver_locale.dart';
|
||||
|
||||
final Map<String, String> _homeserverByContinent = {
|
||||
'af': 'sykorp.com',
|
||||
'as': 'sibnsk.net',
|
||||
'an': 'buyvm.net',
|
||||
'aq': 'arcticfoxes.net',
|
||||
'eu': 'gemeinsam.jetzt',
|
||||
'sa': 'privex.io',
|
||||
'oc': 'mtrx.nz',
|
||||
};
|
||||
|
||||
final Map<String, String> _homeserverByLocale = {
|
||||
'ae': 'sykorp.com',
|
||||
'at': 'gemeinsam.jetzt',
|
||||
'ch': 'pragma-messenger.ch',
|
||||
'de': 'envs.de',
|
||||
'hu': 'grin.hu',
|
||||
'it': 'aria-net.org',
|
||||
'nl': 'nltrix.net',
|
||||
'nz': 'mtrx.nz',
|
||||
'ru': 'rumatrix.org',
|
||||
'us': 'buyvm.net',
|
||||
};
|
||||
|
||||
final _countryCodeContinent = {
|
||||
'af': 'as',
|
||||
'al': 'eu',
|
||||
'aq': 'an',
|
||||
'dz': 'af',
|
||||
'as': 'oc',
|
||||
'ad': 'eu',
|
||||
'ao': 'af',
|
||||
'ag': 'na',
|
||||
'az': 'eu',
|
||||
'ar': 'sa',
|
||||
'au': 'oc',
|
||||
'at': 'eu',
|
||||
'bs': 'na',
|
||||
'bh': 'as',
|
||||
'bd': 'as',
|
||||
'am': 'eu',
|
||||
'bb': 'na',
|
||||
'be': 'eu',
|
||||
'bm': 'na',
|
||||
'bt': 'as',
|
||||
'bo': 'sa',
|
||||
'ba': 'eu',
|
||||
'bw': 'af',
|
||||
'bv': 'an',
|
||||
'br': 'sa',
|
||||
'bz': 'na',
|
||||
'io': 'as',
|
||||
'sb': 'oc',
|
||||
'vg': 'na',
|
||||
'bn': 'as',
|
||||
'bg': 'eu',
|
||||
'mm': 'as',
|
||||
'bi': 'af',
|
||||
'by': 'eu',
|
||||
'kh': 'as',
|
||||
'cm': 'af',
|
||||
'ca': 'na',
|
||||
'cv': 'af',
|
||||
'ky': 'na',
|
||||
'cf': 'af',
|
||||
'lk': 'as',
|
||||
'td': 'af',
|
||||
'cl': 'sa',
|
||||
'cn': 'as',
|
||||
'tw': 'as',
|
||||
'cx': 'as',
|
||||
'cc': 'as',
|
||||
'co': 'sa',
|
||||
'km': 'af',
|
||||
'yt': 'af',
|
||||
'cg': 'af',
|
||||
'cd': 'af',
|
||||
'ck': 'oc',
|
||||
'cr': 'na',
|
||||
'hr': 'eu',
|
||||
'cu': 'na',
|
||||
'cy': 'eu',
|
||||
'cz': 'eu',
|
||||
'bj': 'af',
|
||||
'dk': 'eu',
|
||||
'dm': 'na',
|
||||
'do': 'na',
|
||||
'ec': 'sa',
|
||||
'sv': 'na',
|
||||
'gq': 'af',
|
||||
'et': 'af',
|
||||
'er': 'af',
|
||||
'ee': 'eu',
|
||||
'fo': 'eu',
|
||||
'fk': 'sa',
|
||||
'gs': 'an',
|
||||
'fj': 'oc',
|
||||
'fi': 'eu',
|
||||
'ax': 'eu',
|
||||
'fr': 'eu',
|
||||
'gf': 'sa',
|
||||
'pf': 'oc',
|
||||
'tf': 'an',
|
||||
'dj': 'af',
|
||||
'ga': 'af',
|
||||
'ge': 'eu',
|
||||
'gm': 'af',
|
||||
'ps': 'as',
|
||||
'de': 'eu',
|
||||
'gh': 'af',
|
||||
'gi': 'eu',
|
||||
'ki': 'oc',
|
||||
'gr': 'eu',
|
||||
'gl': 'na',
|
||||
'gd': 'na',
|
||||
'gp': 'na',
|
||||
'gu': 'oc',
|
||||
'gt': 'na',
|
||||
'gn': 'af',
|
||||
'gy': 'sa',
|
||||
'ht': 'na',
|
||||
'hm': 'an',
|
||||
'va': 'eu',
|
||||
'hn': 'na',
|
||||
'hk': 'as',
|
||||
'hu': 'eu',
|
||||
'is': 'eu',
|
||||
'in': 'as',
|
||||
'id': 'as',
|
||||
'ir': 'as',
|
||||
'iq': 'as',
|
||||
'ie': 'eu',
|
||||
'il': 'as',
|
||||
'it': 'eu',
|
||||
'ci': 'af',
|
||||
'jm': 'na',
|
||||
'jp': 'as',
|
||||
'kz': 'eu',
|
||||
'jo': 'as',
|
||||
'ke': 'af',
|
||||
'kp': 'as',
|
||||
'kr': 'as',
|
||||
'kw': 'as',
|
||||
'kg': 'as',
|
||||
'la': 'as',
|
||||
'lb': 'as',
|
||||
'ls': 'af',
|
||||
'lv': 'eu',
|
||||
'lr': 'af',
|
||||
'ly': 'af',
|
||||
'li': 'eu',
|
||||
'lt': 'eu',
|
||||
'lu': 'eu',
|
||||
'mo': 'as',
|
||||
'mg': 'af',
|
||||
'mw': 'af',
|
||||
'my': 'as',
|
||||
'mv': 'as',
|
||||
'ml': 'af',
|
||||
'mt': 'eu',
|
||||
'mq': 'na',
|
||||
'mr': 'af',
|
||||
'mu': 'af',
|
||||
'mx': 'na',
|
||||
'mc': 'eu',
|
||||
'mn': 'as',
|
||||
'md': 'eu',
|
||||
'me': 'eu',
|
||||
'ms': 'na',
|
||||
'ma': 'af',
|
||||
'mz': 'af',
|
||||
'om': 'as',
|
||||
'na': 'af',
|
||||
'nr': 'oc',
|
||||
'np': 'as',
|
||||
'nl': 'eu',
|
||||
'an': 'na',
|
||||
'cw': 'na',
|
||||
'aw': 'na',
|
||||
'sx': 'na',
|
||||
'bq': 'na',
|
||||
'nc': 'oc',
|
||||
'vu': 'oc',
|
||||
'nz': 'oc',
|
||||
'ni': 'na',
|
||||
'ne': 'af',
|
||||
'ng': 'af',
|
||||
'nu': 'oc',
|
||||
'nf': 'oc',
|
||||
'no': 'eu',
|
||||
'mp': 'oc',
|
||||
'um': 'oc',
|
||||
'fm': 'oc',
|
||||
'mh': 'oc',
|
||||
'pw': 'oc',
|
||||
'pk': 'as',
|
||||
'pa': 'na',
|
||||
'pg': 'oc',
|
||||
'py': 'sa',
|
||||
'pe': 'sa',
|
||||
'ph': 'as',
|
||||
'pn': 'oc',
|
||||
'pl': 'eu',
|
||||
'pt': 'eu',
|
||||
'gw': 'af',
|
||||
'tl': 'as',
|
||||
'pr': 'na',
|
||||
'qa': 'as',
|
||||
're': 'af',
|
||||
'ro': 'eu',
|
||||
'ru': 'as',
|
||||
'rw': 'af',
|
||||
'bl': 'na',
|
||||
'sh': 'af',
|
||||
'kn': 'na',
|
||||
'ai': 'na',
|
||||
'lc': 'na',
|
||||
'mf': 'na',
|
||||
'pm': 'na',
|
||||
'vc': 'na',
|
||||
'sm': 'eu',
|
||||
'st': 'af',
|
||||
'sa': 'as',
|
||||
'sn': 'af',
|
||||
'rs': 'eu',
|
||||
'sc': 'af',
|
||||
'sl': 'af',
|
||||
'sg': 'as',
|
||||
'sk': 'eu',
|
||||
'vn': 'as',
|
||||
'si': 'eu',
|
||||
'so': 'af',
|
||||
'za': 'af',
|
||||
'zw': 'af',
|
||||
'es': 'eu',
|
||||
'ss': 'af',
|
||||
'eh': 'af',
|
||||
'sd': 'af',
|
||||
'sr': 'sa',
|
||||
'sj': 'eu',
|
||||
'sz': 'af',
|
||||
'se': 'eu',
|
||||
'ch': 'eu',
|
||||
'sy': 'as',
|
||||
'tj': 'as',
|
||||
'th': 'as',
|
||||
'tg': 'af',
|
||||
'tk': 'oc',
|
||||
'to': 'oc',
|
||||
'tt': 'na',
|
||||
'ae': 'as',
|
||||
'tn': 'af',
|
||||
'tr': 'as',
|
||||
'tm': 'as',
|
||||
'tc': 'na',
|
||||
'tv': 'oc',
|
||||
'ug': 'af',
|
||||
'ua': 'eu',
|
||||
'mk': 'eu',
|
||||
'eg': 'af',
|
||||
'gb': 'eu',
|
||||
'gg': 'eu',
|
||||
'je': 'eu',
|
||||
'im': 'eu',
|
||||
'tz': 'af',
|
||||
'us': 'na',
|
||||
'vi': 'na',
|
||||
'bf': 'af',
|
||||
'uy': 'sa',
|
||||
'uz': 'as',
|
||||
've': 'sa',
|
||||
'wf': 'oc',
|
||||
'ws': 'oc',
|
||||
'ye': 'as',
|
||||
'zm': 'af',
|
||||
'xx': 'oc',
|
||||
'xe': 'as',
|
||||
'xd': 'as',
|
||||
'xs': 'as',
|
||||
};
|
@ -1,4 +1,5 @@
|
||||
import 'dart:async';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
@ -7,6 +8,7 @@ import 'package:matrix_homeserver_recommendations/matrix_homeserver_recommendati
|
||||
import 'package:vrouter/vrouter.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/config/homeserver_locale.dart';
|
||||
import 'package:fluffychat/pages/homeserver_picker/homeserver_bottom_sheet.dart';
|
||||
import 'package:fluffychat/pages/homeserver_picker/homeserver_picker_view.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
@ -28,6 +30,7 @@ class HomeserverPickerController extends State<HomeserverPicker> {
|
||||
String? error;
|
||||
List<HomeserverBenchmarkResult>? benchmarkResults;
|
||||
bool displayServerList = false;
|
||||
|
||||
bool get loadingHomeservers =>
|
||||
AppConfig.allowOtherHomeservers && benchmarkResults == null;
|
||||
String searchTerm = '';
|
||||
@ -129,6 +132,12 @@ class HomeserverPickerController extends State<HomeserverPicker> {
|
||||
}
|
||||
}
|
||||
|
||||
void _defaultHomeserverByLocale() {
|
||||
final serverMatcher = HomeserverLocale(window.locale);
|
||||
setState(() => homeserverController.text =
|
||||
serverMatcher.choose() ?? AppConfig.defaultHomeserver);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
homeserverFocusNode.removeListener(_updateFocus);
|
||||
@ -138,6 +147,10 @@ class HomeserverPickerController extends State<HomeserverPicker> {
|
||||
@override
|
||||
void initState() {
|
||||
homeserverFocusNode.addListener(_updateFocus);
|
||||
if (AppConfig.useLocaleBasedHomeserver) {
|
||||
WidgetsBinding.instance
|
||||
.addPostFrameCallback((timeStamp) => _defaultHomeserverByLocale());
|
||||
}
|
||||
super.initState();
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,13 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:animations/animations.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:vrouter/vrouter.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/config/themes.dart';
|
||||
import 'package:fluffychat/pages/homeserver_picker/homeserver_tile.dart';
|
||||
import 'package:fluffychat/utils/platform_infos.dart';
|
||||
import 'package:fluffychat/widgets/layouts/login_scaffold.dart';
|
||||
import 'homeserver_picker.dart';
|
||||
@ -63,40 +65,58 @@ class HomeserverPickerView extends StatelessWidget {
|
||||
BorderRadius.circular(AppConfig.borderRadius),
|
||||
color: Colors.white.withAlpha(200),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
child: benchmarkResults == null
|
||||
? const Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(16.0),
|
||||
child: CircularProgressIndicator.adaptive(),
|
||||
))
|
||||
: Column(
|
||||
children: controller.filteredHomeservers
|
||||
.map(
|
||||
(server) => ListTile(
|
||||
trailing: IconButton(
|
||||
icon: const Icon(
|
||||
Icons.info_outlined,
|
||||
color: Colors.black,
|
||||
),
|
||||
onPressed: () =>
|
||||
controller.showServerInfo(server),
|
||||
child: PageTransitionSwitcher(
|
||||
transitionBuilder: (
|
||||
Widget child,
|
||||
Animation<double> primaryAnimation,
|
||||
Animation<double> secondaryAnimation,
|
||||
) {
|
||||
return SharedAxisTransition(
|
||||
animation: primaryAnimation,
|
||||
secondaryAnimation: secondaryAnimation,
|
||||
transitionType: SharedAxisTransitionType.scaled,
|
||||
child: child,
|
||||
fillColor: Colors.transparent,
|
||||
);
|
||||
},
|
||||
child: ListTileTheme(
|
||||
data: const ListTileThemeData(
|
||||
iconColor: Colors.black,
|
||||
textColor: Colors.black,
|
||||
),
|
||||
key: ValueKey(benchmarkResults),
|
||||
child: benchmarkResults == null
|
||||
? Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const CircularProgressIndicator
|
||||
.adaptive(),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.rocket),
|
||||
title: Text(L10n.of(context)!
|
||||
.benchmarkingHomeserver),
|
||||
),
|
||||
onTap: () => controller.setServer(
|
||||
server.homeserver.baseUrl.host),
|
||||
title: Text(
|
||||
server.homeserver.baseUrl.host,
|
||||
style: const TextStyle(
|
||||
color: Colors.black),
|
||||
),
|
||||
subtitle: Text(
|
||||
server.homeserver.description ?? '',
|
||||
style: TextStyle(
|
||||
color: Colors.grey.shade700),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
],
|
||||
),
|
||||
))
|
||||
: ListView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemCount:
|
||||
controller.filteredHomeservers.length,
|
||||
itemBuilder: (context, index) {
|
||||
final server =
|
||||
controller.filteredHomeservers[index];
|
||||
return HomeserverTile(
|
||||
server: server, controller: controller);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Wrap(
|
||||
|
30
lib/pages/homeserver_picker/homeserver_tile.dart
Normal file
30
lib/pages/homeserver_picker/homeserver_tile.dart
Normal file
@ -0,0 +1,30 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:matrix_homeserver_recommendations/matrix_homeserver_recommendations.dart';
|
||||
|
||||
import 'package:fluffychat/pages/homeserver_picker/homeserver_picker.dart';
|
||||
|
||||
class HomeserverTile extends StatelessWidget {
|
||||
final HomeserverBenchmarkResult server;
|
||||
final HomeserverPickerController controller;
|
||||
|
||||
const HomeserverTile(
|
||||
{Key? key, required this.server, required this.controller})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListTile(
|
||||
trailing: IconButton(
|
||||
icon: const Icon(Icons.info_outlined),
|
||||
onPressed: () => controller.showServerInfo(server),
|
||||
),
|
||||
onTap: () => controller.setServer(server.homeserver.baseUrl.host),
|
||||
title: Text(server.homeserver.baseUrl.host),
|
||||
subtitle: Text(
|
||||
server.homeserver.description ?? '',
|
||||
style: TextStyle(color: Colors.grey.shade700),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user