Merge branch 'main' of https://gitlab.com/ChristianPauly/fluffychat-flutter into yiffed
This commit is contained in:
commit
2a3cb73e32
|
@ -1,12 +1,18 @@
|
|||
# Version 0.20.0 - 2020-??-??
|
||||
### Features
|
||||
- Added translations: Arabic
|
||||
- Add ability to enable / disable emotes globally
|
||||
- Add ability to manage emote packs with different state keys
|
||||
- Add swipe to reply - Thanks @inexcode
|
||||
- Initial support for compiling to desktop
|
||||
- Initial snap metadata - Thanks @RAOF_47
|
||||
### Changes
|
||||
- Re-scale images in a separate isolate to prevent the UI from freezing
|
||||
- URLs without https:// now linkify
|
||||
### Fixes
|
||||
- Fix amoled / theme settings not always saving properly
|
||||
- Show device name in account information correctly
|
||||
- Fix tapping on aliases / room pills not always working
|
||||
|
||||
# Version 0.19.0 - 2020-09-21
|
||||
### Features
|
||||
|
|
|
@ -3,7 +3,6 @@ import 'package:famedlysdk/famedlysdk.dart';
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../utils/platform_infos.dart';
|
||||
import '../utils/string_color.dart';
|
||||
import 'matrix.dart';
|
||||
|
||||
|
@ -28,31 +27,49 @@ class Avatar extends StatelessWidget {
|
|||
Matrix.of(context).client,
|
||||
width: size * MediaQuery.of(context).devicePixelRatio,
|
||||
height: size * MediaQuery.of(context).devicePixelRatio,
|
||||
method: ThumbnailMethod.scale,
|
||||
);
|
||||
final src = thumbnail;
|
||||
var fallbackLetters = '@';
|
||||
if ((name?.length ?? 0) >= 2) {
|
||||
fallbackLetters = name.substring(0, 2);
|
||||
fallbackLetters = String.fromCharCodes(name.runes, 0, 2);
|
||||
} else if ((name?.length ?? 0) == 1) {
|
||||
fallbackLetters = name;
|
||||
}
|
||||
final textWidget = Center(
|
||||
child: Text(
|
||||
fallbackLetters,
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
);
|
||||
final noPic = mxContent == null || mxContent.toString().isEmpty;
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
child: CircleAvatar(
|
||||
radius: size / 2,
|
||||
backgroundImage: !noPic
|
||||
? PlatformInfos.isBetaDesktop
|
||||
? NetworkImage(src)
|
||||
: CachedNetworkImageProvider(src)
|
||||
: null,
|
||||
backgroundColor: noPic
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(size / 2),
|
||||
child: Container(
|
||||
width: size,
|
||||
height: size,
|
||||
color: noPic
|
||||
? name?.lightColor ?? Theme.of(context).secondaryHeaderColor
|
||||
: Theme.of(context).secondaryHeaderColor,
|
||||
child: noPic
|
||||
? Text(fallbackLetters, style: TextStyle(color: Colors.white))
|
||||
: null,
|
||||
? textWidget
|
||||
: CachedNetworkImage(
|
||||
imageUrl: src,
|
||||
fit: BoxFit.cover,
|
||||
width: size,
|
||||
height: size,
|
||||
placeholder: (c, s) => Stack(
|
||||
children: [
|
||||
Center(child: CircularProgressIndicator(strokeWidth: 2)),
|
||||
textWidget,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -49,13 +49,7 @@ class ContentBanner extends StatelessWidget {
|
|||
opacity: 0.75,
|
||||
child: !loading
|
||||
? mxContent != null
|
||||
? PlatformInfos.isBetaDesktop
|
||||
? Image.network(
|
||||
src,
|
||||
height: 300,
|
||||
fit: BoxFit.cover,
|
||||
)
|
||||
: CachedNetworkImage(
|
||||
? CachedNetworkImage(
|
||||
imageUrl: src,
|
||||
height: 300,
|
||||
fit: BoxFit.cover,
|
||||
|
|
|
@ -128,15 +128,9 @@ class _ImageBubbleState extends State<ImageBubble> {
|
|||
width: 800,
|
||||
height: 800,
|
||||
method: ThumbnailMethod.scale);
|
||||
renderWidget = PlatformInfos.isBetaDesktop
|
||||
? Image.network(
|
||||
src,
|
||||
fit: widget.fit,
|
||||
)
|
||||
: CachedNetworkImage(
|
||||
renderWidget = CachedNetworkImage(
|
||||
imageUrl: src,
|
||||
placeholder: (context, url) =>
|
||||
generatePlaceholderWidget(),
|
||||
placeholder: (context, url) => generatePlaceholderWidget(),
|
||||
fit: widget.fit,
|
||||
);
|
||||
} else {
|
||||
|
|
|
@ -150,13 +150,7 @@ class InputBar extends StatelessWidget {
|
|||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
PlatformInfos.isBetaDesktop
|
||||
? Image.network(
|
||||
url,
|
||||
width: size,
|
||||
height: size,
|
||||
)
|
||||
: CachedNetworkImage(
|
||||
CachedNetworkImage(
|
||||
imageUrl: url,
|
||||
width: size,
|
||||
height: size,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:bot_toast/bot_toast.dart';
|
||||
import 'package:circular_check_box/circular_check_box.dart';
|
||||
import 'package:famedlysdk/famedlysdk.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
@ -12,6 +13,7 @@ import '../avatar.dart';
|
|||
import '../dialogs/send_file_dialog.dart';
|
||||
import '../dialogs/simple_dialogs.dart';
|
||||
import '../matrix.dart';
|
||||
import '../mouse_over_builder.dart';
|
||||
import '../theme_switcher.dart';
|
||||
|
||||
class ChatListItem extends StatelessWidget {
|
||||
|
@ -127,7 +129,20 @@ class ChatListItem extends StatelessWidget {
|
|||
color: chatListItemColor(context, activeChat, selected),
|
||||
child: ListTile(
|
||||
onLongPress: onLongPress,
|
||||
leading: Avatar(room.avatar, room.displayname),
|
||||
leading: MouseOverBuilder(
|
||||
builder: (context, hover) =>
|
||||
onLongPress != null && (hover || selected)
|
||||
? Container(
|
||||
width: Avatar.defaultSize,
|
||||
height: Avatar.defaultSize,
|
||||
alignment: Alignment.center,
|
||||
child: CircularCheckBox(
|
||||
value: selected,
|
||||
onChanged: (_) => onLongPress(),
|
||||
),
|
||||
)
|
||||
: Avatar(room.avatar, room.displayname),
|
||||
),
|
||||
title: Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
|
|
|
@ -5,6 +5,7 @@ import 'package:flutter_gen/gen_l10n/l10n.dart';
|
|||
import '../../utils/date_time_extension.dart';
|
||||
import '../../utils/event_extension.dart';
|
||||
import '../../utils/string_color.dart';
|
||||
import '../adaptive_page_layout.dart';
|
||||
import '../avatar.dart';
|
||||
import '../dialogs/simple_dialogs.dart';
|
||||
import '../matrix.dart';
|
||||
|
@ -86,6 +87,8 @@ class Message extends StatelessWidget {
|
|||
color: color,
|
||||
borderRadius: BorderRadius.circular(radius),
|
||||
),
|
||||
constraints:
|
||||
BoxConstraints(maxWidth: AdaptivePageLayout.defaultMinWidth),
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
Column(
|
||||
|
|
|
@ -8,6 +8,10 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:universal_html/prefer_universal/html.dart' as html;
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
/*import 'package:fluffychat/views/chat.dart';
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:dbus/dbus.dart';
|
||||
import 'package:desktop_notifications/desktop_notifications.dart';*/
|
||||
|
||||
import '../utils/app_route.dart';
|
||||
import '../utils/beautify_string_extension.dart';
|
||||
|
@ -179,9 +183,10 @@ class MatrixState extends State<Matrix> {
|
|||
|
||||
bool webHasFocus = true;
|
||||
|
||||
void _showWebNotification(EventUpdate eventUpdate) async {
|
||||
if (webHasFocus && activeRoomId == eventUpdate.roomID) return;
|
||||
final room = client.getRoomById(eventUpdate.roomID);
|
||||
void _showLocalNotification(EventUpdate eventUpdate) async {
|
||||
final roomId = eventUpdate.roomID;
|
||||
if (webHasFocus && activeRoomId == roomId) return;
|
||||
final room = client.getRoomById(roomId);
|
||||
if (room.notificationCount == 0) return;
|
||||
final event = Event.fromJson(eventUpdate.content, room);
|
||||
final body = event.getLocalizedBody(
|
||||
|
@ -189,6 +194,11 @@ class MatrixState extends State<Matrix> {
|
|||
withSenderNamePrefix:
|
||||
!room.isDirectChat || room.lastEvent.senderId == client.userID,
|
||||
);
|
||||
final icon = event.sender.avatarUrl?.getThumbnail(client,
|
||||
width: 64, height: 64, method: ThumbnailMethod.crop) ??
|
||||
room.avatar?.getThumbnail(client,
|
||||
width: 64, height: 64, method: ThumbnailMethod.crop);
|
||||
if (kIsWeb) {
|
||||
html.AudioElement()
|
||||
..src = 'assets/assets/sounds/notification.wav'
|
||||
..autoplay = true
|
||||
|
@ -196,12 +206,28 @@ class MatrixState extends State<Matrix> {
|
|||
html.Notification(
|
||||
room.getLocalizedDisplayname(MatrixLocals(L10n.of(context))),
|
||||
body: body,
|
||||
icon: event.sender.avatarUrl?.getThumbnail(client,
|
||||
width: 64, height: 64, method: ThumbnailMethod.crop) ??
|
||||
room.avatar?.getThumbnail(client,
|
||||
width: 64, height: 64, method: ThumbnailMethod.crop),
|
||||
icon: icon,
|
||||
);
|
||||
} else if (Platform.isLinux) {
|
||||
/*var sessionBus = DBusClient.session();
|
||||
var client = NotificationClient(sessionBus);
|
||||
_linuxNotificationIds[roomId] = await client.notify(
|
||||
room.getLocalizedDisplayname(MatrixLocals(L10n.of(context))),
|
||||
body: body,
|
||||
replacesID: _linuxNotificationIds[roomId] ?? -1,
|
||||
appName: AppConfig.applicationName,
|
||||
actionCallback: (_) => Navigator.of(context).pushAndRemoveUntil(
|
||||
AppRoute.defaultRoute(
|
||||
context,
|
||||
ChatView(roomId),
|
||||
),
|
||||
(r) => r.isFirst),
|
||||
);
|
||||
await sessionBus.close();*/
|
||||
}
|
||||
}
|
||||
|
||||
//final Map<String, int> _linuxNotificationIds = {};
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
@ -299,7 +325,8 @@ class MatrixState extends State<Matrix> {
|
|||
if (kIsWeb) {
|
||||
onFocusSub = html.window.onFocus.listen((_) => webHasFocus = true);
|
||||
onBlurSub = html.window.onBlur.listen((_) => webHasFocus = false);
|
||||
|
||||
}
|
||||
if (kIsWeb || Platform.isLinux) {
|
||||
client.onSync.stream.first.then((s) {
|
||||
html.Notification.requestPermission();
|
||||
onNotification ??= client.onEvent.stream
|
||||
|
@ -308,7 +335,7 @@ class MatrixState extends State<Matrix> {
|
|||
[EventTypes.Message, EventTypes.Sticker, EventTypes.Encrypted]
|
||||
.contains(e.eventType) &&
|
||||
e.content['sender'] != client.userID)
|
||||
.listen(_showWebNotification);
|
||||
.listen(_showLocalNotification);
|
||||
});
|
||||
}
|
||||
super.initState();
|
||||
|
|
|
@ -93,12 +93,7 @@ class _Reaction extends StatelessWidget {
|
|||
content = Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
PlatformInfos.isBetaDesktop
|
||||
? Image.network(
|
||||
src,
|
||||
height: fontSize,
|
||||
)
|
||||
: CachedNetworkImage(
|
||||
CachedNetworkImage(
|
||||
imageUrl: src,
|
||||
height: fontSize,
|
||||
),
|
||||
|
|
28
lib/components/mouse_over_builder.dart
Normal file
28
lib/components/mouse_over_builder.dart
Normal file
|
@ -0,0 +1,28 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class MouseOverBuilder extends StatefulWidget {
|
||||
final Function(BuildContext, bool) builder;
|
||||
|
||||
const MouseOverBuilder({Key key, this.builder}) : super(key: key);
|
||||
@override
|
||||
_MouseOverBuilderState createState() => _MouseOverBuilderState();
|
||||
}
|
||||
|
||||
class _MouseOverBuilderState extends State<MouseOverBuilder> {
|
||||
bool _hover = false;
|
||||
|
||||
void _toggleHover(bool hover) {
|
||||
if (_hover != hover) {
|
||||
setState(() => _hover = hover);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MouseRegion(
|
||||
onEnter: (_) => _toggleHover(true),
|
||||
onExit: (_) => _toggleHover(false),
|
||||
child: widget.builder != null ? widget.builder(context, _hover) : null,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -683,15 +683,12 @@ class _ChatState extends State<_Chat> {
|
|||
body: Stack(
|
||||
children: <Widget>[
|
||||
if (Matrix.of(context).wallpaper != null)
|
||||
Opacity(
|
||||
opacity: 0.66,
|
||||
child: Image.file(
|
||||
Image.file(
|
||||
Matrix.of(context).wallpaper,
|
||||
height: double.infinity,
|
||||
width: double.infinity,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
Column(
|
||||
children: <Widget>[
|
||||
ConnectionStatusHeader(),
|
||||
|
@ -935,8 +932,7 @@ class _ChatState extends State<_Chat> {
|
|||
room.canSendDefaultMessages && room.membership == Membership.join
|
||||
? Container(
|
||||
decoration: BoxDecoration(
|
||||
color:
|
||||
Theme.of(context).backgroundColor.withOpacity(0.8),
|
||||
color: Theme.of(context).backgroundColor,
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
|
|
|
@ -420,9 +420,7 @@ class _ChatListState extends State<ChatList> {
|
|||
),
|
||||
),
|
||||
),
|
||||
floatingActionButton:
|
||||
(AdaptivePageLayout.columnMode(context) ||
|
||||
selectMode != SelectMode.normal)
|
||||
floatingActionButton: AdaptivePageLayout.columnMode(context)
|
||||
? null
|
||||
: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
|
@ -441,8 +439,7 @@ class _ChatListState extends State<ChatList> {
|
|||
SizedBox(height: 16.0),
|
||||
FloatingActionButton(
|
||||
child: Icon(Icons.add),
|
||||
backgroundColor:
|
||||
Theme.of(context).primaryColor,
|
||||
backgroundColor: Theme.of(context).primaryColor,
|
||||
onPressed: () => Navigator.of(context)
|
||||
.pushAndRemoveUntil(
|
||||
AppRoute.defaultRoute(
|
||||
|
@ -532,11 +529,7 @@ class _ChatListState extends State<ChatList> {
|
|||
(BuildContext context, int i) {
|
||||
if (i == 0) {
|
||||
final displayPresences =
|
||||
Matrix.of(context)
|
||||
.userStatuses
|
||||
.isNotEmpty &&
|
||||
selectMode ==
|
||||
SelectMode.normal;
|
||||
selectMode != SelectMode.share;
|
||||
final displayShareStatus =
|
||||
selectMode ==
|
||||
SelectMode.share &&
|
||||
|
|
|
@ -416,14 +416,7 @@ class _EmoteImage extends StatelessWidget {
|
|||
height: size * devicePixelRatio,
|
||||
method: ThumbnailMethod.scale,
|
||||
);
|
||||
return PlatformInfos.isBetaDesktop
|
||||
? Image.network(
|
||||
url,
|
||||
fit: BoxFit.contain,
|
||||
width: size,
|
||||
height: size,
|
||||
)
|
||||
: CachedNetworkImage(
|
||||
return CachedNetworkImage(
|
||||
imageUrl: url,
|
||||
fit: BoxFit.contain,
|
||||
width: size,
|
||||
|
|
|
@ -19,7 +19,7 @@ static void my_application_activate(GApplication* application) {
|
|||
gtk_header_bar_set_title(header_bar, "fluffychat");
|
||||
gtk_header_bar_set_show_close_button(header_bar, TRUE);
|
||||
gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
|
||||
gtk_window_set_default_size(window, 1280, 720);
|
||||
gtk_window_set_default_size(window, 802, 520);
|
||||
gtk_widget_show(GTK_WIDGET(window));
|
||||
|
||||
g_autoptr(FlDartProject) project = fl_dart_project_new();
|
||||
|
|
31
pubspec.lock
31
pubspec.lock
|
@ -77,7 +77,7 @@ packages:
|
|||
name: cached_network_image
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.3.2+1"
|
||||
version: "2.3.3"
|
||||
canonical_json:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -99,6 +99,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0-nullsafety.1"
|
||||
circular_check_box:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: circular_check_box
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
cli_util:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -188,7 +195,7 @@ packages:
|
|||
description:
|
||||
path: "."
|
||||
ref: yiffed
|
||||
resolved-ref: c1791edd4d9788d353c618cf1717a88d6c3b547b
|
||||
resolved-ref: d9bc92d6543e51845ef384ee7650fcb3428d0718
|
||||
url: "https://github.com/innereq/famedlysdk-fork.git"
|
||||
source: git
|
||||
version: "0.0.1"
|
||||
|
@ -233,7 +240,7 @@ packages:
|
|||
name: firebase
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "7.3.1"
|
||||
version: "7.3.2"
|
||||
firebase_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -280,7 +287,7 @@ packages:
|
|||
name: flutter_cache_manager
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.4.2"
|
||||
version: "2.0.0"
|
||||
flutter_keyboard_visibility:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -301,7 +308,7 @@ packages:
|
|||
name: flutter_local_notifications
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.0+1"
|
||||
version: "2.0.1"
|
||||
flutter_local_notifications_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -428,7 +435,7 @@ packages:
|
|||
name: image_picker
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.6.7+11"
|
||||
version: "0.6.7+12"
|
||||
image_picker_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -477,7 +484,7 @@ packages:
|
|||
name: localstorage
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.2+5"
|
||||
version: "3.0.3+6"
|
||||
logging:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -512,7 +519,7 @@ packages:
|
|||
name: matrix_link_text
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.1.5"
|
||||
version: "0.2.0"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -626,7 +633,7 @@ packages:
|
|||
name: path_provider
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.6.18"
|
||||
version: "1.6.21"
|
||||
path_provider_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -759,7 +766,7 @@ packages:
|
|||
name: share
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.6.5+2"
|
||||
version: "0.6.5+3"
|
||||
shelf:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -834,7 +841,7 @@ packages:
|
|||
name: sqlite3
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.1.6"
|
||||
version: "0.1.7"
|
||||
sqlite3_flutter_libs:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -946,7 +953,7 @@ packages:
|
|||
name: url_launcher
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.7.2"
|
||||
version: "5.7.5"
|
||||
url_launcher_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -34,10 +34,10 @@ dependencies:
|
|||
file_picker_cross: ^4.2.2
|
||||
image_picker: ^0.6.7+11
|
||||
url_launcher: ^5.7.2
|
||||
cached_network_image: ^2.3.2+1
|
||||
cached_network_image: ^2.3.3
|
||||
firebase_messaging: ^7.0.2
|
||||
flutter_local_notifications: ^2.0.0+1
|
||||
matrix_link_text: ^0.1.5
|
||||
matrix_link_text: ^0.2.0
|
||||
path_provider: ^1.5.1
|
||||
webview_flutter: ^0.3.19+9
|
||||
share: ^0.6.3+5
|
||||
|
@ -60,6 +60,7 @@ dependencies:
|
|||
flutter_olm: ^1.0.1
|
||||
intl: ^0.16.1
|
||||
intl_translation: ^0.17.9
|
||||
circular_check_box: ^1.0.4
|
||||
flutter_localizations:
|
||||
sdk: flutter
|
||||
sqflite: ^1.1.7 # Still used to obtain the database location
|
||||
|
|
Loading…
Reference in a new issue