Skip to content

Commit

Permalink
Merge pull request #891 from BlueBubblesApp/zach/beta
Browse files Browse the repository at this point in the history
v1.1.0 Release
  • Loading branch information
zlshames committed Jun 18, 2021
2 parents d0793a6 + b65537f commit e6e84b9
Show file tree
Hide file tree
Showing 24 changed files with 610 additions and 267 deletions.
2 changes: 1 addition & 1 deletion android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ android {
// version code: 1 0114 0 70 64

//noinspection AccidentalOctal
versionCode 11000070
versionCode 11100064
versionName flutterVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

Expand Down
19 changes: 19 additions & 0 deletions assets/changelog/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,24 @@

Below are the last few BlueBubbles App release changelogs

## v1.1.0

* New Feature: Adds back button to image viewer
* New Feature: Adds contact addresses under their name in the message details page
* New Feature: Adds haptic feedback to camera preview
* New Feature: Ability to mark all chats as read via the 3 dot menu
* New Feature: Message details popup now fades in for a smoother animation
* New Feature: Attachment downloader now animates progress instead of "jumping" progress
* UX: Increases chat page size to 12 for material skin to avoid visual stutters during chat loading
* Bug Fix: Fixes issue where avatar colors were editable even when the option was disabled
* Bug Fix: Fixes issue where you wouldn't be able to delete a message if it wasn't sent
* Bug Fix: Fixes grey box issues in reactions popup
* Bug Fix: Fixes issue where your own reaction wouldn't show an avatar
* Bug Fix: Fixes grey box issues for incoming video attachments
* Bug Fix: Manual mark chat as read button now only shows when auto-mark chat as read is off
* Bug Fix: Fixes attachment details page not having bottom margin/spacing, thus interfering with the navigation bar
* Bug Fix: Fixes attachment downloading issues in the details page

## v1.0.0

This version encompasses all release candidates for the unreleased v0.1.16. I have rolled up and summarized all the changes since v0.1.15 below:
Expand All @@ -27,6 +45,7 @@ This version encompasses all release candidates for the unreleased v0.1.16. I ha
* New Feature: Attachment Preview Quality Slider
* New Feature: Colorblind Mode
* New Feature: Ability to restart the BlueBubbles Server, remotely
* New Feature: Show connection indicator in chat
* Bug Fix: Fixes issue where the contact address would not auto-fill the fields when creating a new contact
* Bug Fix: Fixes placeholder text not updating
* Bug Fix: Fixes message subject color
Expand Down
18 changes: 17 additions & 1 deletion lib/blocs/chat_bloc.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:async';
import 'dart:typed_data';

import 'package:bluebubbles/helpers/constants.dart';
import 'package:bluebubbles/helpers/utils.dart';
import 'package:bluebubbles/managers/attachment_info_bloc.dart';
import 'package:bluebubbles/managers/contact_manager.dart';
Expand Down Expand Up @@ -57,7 +58,7 @@ class ChatBloc {
}

int get pageSize {
return (SettingsManager().settings.denseChatTiles) ? 12 : 10;
return (SettingsManager().settings.denseChatTiles || SettingsManager().settings.skin != Skins.IOS) ? 12 : 10;
}

Future<Chat> getChat(String guid) async {
Expand Down Expand Up @@ -157,6 +158,21 @@ class ChatBloc {
await updateShareTarget(chat);
}

Future<void> markAllAsRead() async {
// Enumerate the unread chats
List<Chat> unread = this.chats.where((element) => element.hasUnreadMessage).toList();

// Mark them as unread
for (Chat chat in unread) {
await chat.setUnreadStatus(false);
}

// Update their position in the chat list
for (Chat chat in unread) {
this.updateChatPosition(chat);
}
}

Future<void> updateAllShareTargets() async {
List<Chat> chats = this.chats.sublist(0);
chats.sort(Chat.sort);
Expand Down
5 changes: 3 additions & 2 deletions lib/blocs/setup_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,10 @@ class SetupBloc {

await syncChat(chat);
addOutput("Finished syncing chat, '${chat.chatIdentifier}'", SetupOutputType.LOG);
} catch (ex) {
} catch (ex, stacktrace) {
if (chat != null) {
addOutput("Failed to sync chat, '${chat.chatIdentifier}'", SetupOutputType.ERROR);
addOutput(stacktrace.toString(), SetupOutputType.ERROR);
} else {
addOutput("Failed to save chat data, '${item.toString()}'", SetupOutputType.ERROR);
}
Expand Down Expand Up @@ -186,7 +187,7 @@ class SetupBloc {
];

List<dynamic> messages = await SocketManager().getChatMessages(params);
addOutput("Received ${messages?.length} messages for chat, '${chat.chatIdentifier}'!", SetupOutputType.LOG);
addOutput("Received ${messages?.length ?? 0} messages for chat, '${chat.chatIdentifier}'!", SetupOutputType.LOG);

// Since we got the messages in desc order, we want to reverse it.
// Reversing it will add older messages before newer one. This should help fix
Expand Down
11 changes: 10 additions & 1 deletion lib/helpers/attachment_helper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,16 @@ class AttachmentHelper {
List<Item> phones = <Item>[];
_contact.keys.forEach((String key) {
if (key.contains("EMAIL")) {
String label = key.contains("type=") ? key.split("type=")[2].replaceAll(";", "") : "HOME";
String label = 'HOME';

// Try to parse out the type of email
if (key.contains('type=')) {
List<String> splitData = key.split('type=');
if (splitData.length >= 2) {
label = splitData[2].replaceAll(';', '');
}
}

emails.add(
Item(
value: (_contact[key] as Map<String, dynamic>)["value"],
Expand Down
13 changes: 12 additions & 1 deletion lib/helpers/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,19 @@ Future<String> formatPhoneNumber(String str) async {

Future<List<String>> getCompareOpts(Handle handle) async {
if (handle.address.contains('@')) return [handle.address];

// Build a list of formatted address (max: 3)
String formatted = handle.address.toString();
List<String> opts = [formatted, formatted.substring(1), formatted.substring(2)];
List<String> opts = [];
int maxOpts = 4; // This is relatively arbitrary
for (int i = 0; i < formatted.length; i += 1) {
String val = formatted.substring(i);
if (val.length == 0) break;

opts.add(val);
if (i + 1 >= maxOpts) break;
}

Map<String, dynamic> parsed = await parsePhoneNumber(handle.address, handle.country ?? "US");
opts.addAll(parsed.values.map((item) => item.toString()).where((item) => item != 'fixedOrMobile'));
return opts;
Expand Down
22 changes: 15 additions & 7 deletions lib/layouts/conversation_details/attachment_details_card.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'dart:typed_data';
import 'package:bluebubbles/helpers/attachment_downloader.dart';
import 'package:bluebubbles/helpers/attachment_helper.dart';
import 'package:bluebubbles/layouts/image_viewer/attachmet_fullscreen_viewer.dart';
import 'package:bluebubbles/layouts/widgets/circle_progress_bar.dart';
import 'package:bluebubbles/layouts/widgets/message_widget/message_content/media_players/regular_file_opener.dart';
import 'package:bluebubbles/layouts/widgets/theme_switcher/theme_switcher.dart';
import 'package:bluebubbles/managers/current_chat.dart';
Expand Down Expand Up @@ -113,13 +114,20 @@ class _AttachmentDetailsCardState extends State<AttachmentDetailsCard> {
: StreamBuilder<Object>(
stream: SocketManager().attachmentDownloaders[attachment.guid].stream,
builder: (context, snapshot) {
return CircularProgressIndicator(
backgroundColor: Colors.grey,
valueColor: AlwaysStoppedAnimation(Colors.white),
value: snapshot.hasData && snapshot.data is Map
? (snapshot.data as Map<String, double>)["Progress"]
: 0,
);
double value = 0;
if (snapshot.hasData) {
if (snapshot.data is Map) {
value = (snapshot.data as Map<String, num>)["progress"].toDouble();
} else if (snapshot.data is File) {
value = 1;
}
}

return Container(
height: 40,
width: 40,
child: CircleProgressBar(
foregroundColor: Colors.white, backgroundColor: Colors.grey, value: value));
},
),
],
Expand Down
17 changes: 17 additions & 0 deletions lib/layouts/conversation_details/contact_tile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,23 @@ class _ContactTileState extends State<ContactTile> {
style: Theme.of(context).textTheme.bodyText1,
);
}),
subtitle: (contact == null)
? null
: FutureBuilder(
future: formatPhoneNumber(widget.handle?.address ?? ""),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Text(
widget.handle?.address ?? "",
style: Theme.of(context).textTheme.subtitle1.apply(fontSizeDelta: -0.5),
);
}

return Text(
snapshot.data,
style: Theme.of(context).textTheme.subtitle1.apply(fontSizeDelta: -0.5),
);
}),
leading: ContactAvatarWidget(
handle: widget.handle,
borderThickness: 0.1,
Expand Down
67 changes: 53 additions & 14 deletions lib/layouts/conversation_details/conversation_details.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import 'package:bluebubbles/managers/event_dispatcher.dart';
import 'package:bluebubbles/managers/settings_manager.dart';
import 'package:bluebubbles/repository/models/attachment.dart';
import 'package:bluebubbles/repository/models/chat.dart';
import 'package:bluebubbles/repository/models/handle.dart';
import 'package:bluebubbles/repository/models/message.dart';
import 'package:bluebubbles/socket_manager.dart';
import 'package:flutter/cupertino.dart';
Expand All @@ -34,6 +35,20 @@ class _ConversationDetailsState extends State<ConversationDetails> {
List<Attachment> attachmentsForChat = <Attachment>[];
bool isClearing = false;
bool isCleared = false;
int maxPageSize = 5;
bool showMore = false;

bool get shouldShowMore {
return chat.participants.length > maxPageSize;
}

List<Handle> get participants {
// If we are showing all, return everything
if (showMore) return chat.participants;

// If we aren't showing all, show the max we can show
return chat.participants.length > maxPageSize ? chat.participants.sublist(0, maxPageSize) : chat.participants;
}

@override
void initState() {
Expand Down Expand Up @@ -130,21 +145,44 @@ class _ConversationDetailsState extends State<ConversationDetails> {
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return ContactTile(
key: Key(chat.participants[index].id.toString()),
handle: chat.participants[index],
chat: chat,
updateChat: (Chat newChat) {
chat = newChat;
if (this.mounted) setState(() {});
delegate: SliverChildBuilderDelegate((context, index) {
if (index >= participants.length && shouldShowMore) {
return ListTile(
onTap: () {
if (!this.mounted) return;
setState(() {
showMore = !showMore;
});
},
canBeRemoved: chat.participants.length > 1,
leading: Text(
showMore ? "Show less" : "Show more",
style: TextStyle(
color: Theme.of(context).primaryColor,
),
),
trailing: Padding(
padding: EdgeInsets.only(right: 15),
child: Icon(
Icons.more_horiz,
color: Theme.of(context).primaryColor,
),
),
);
},
childCount: chat.participants.length,
),
}

if (index >= chat.participants.length) return Container();

return ContactTile(
key: Key(chat.participants[index].id.toString()),
handle: chat.participants[index],
chat: chat,
updateChat: (Chat newChat) {
chat = newChat;
if (this.mounted) setState(() {});
},
canBeRemoved: chat.participants.length > 1,
);
}, childCount: participants.length + 1),
),
// SliverToBoxAdapter(
// child: chat.participants.length > 1
Expand Down Expand Up @@ -382,7 +420,8 @@ class _ConversationDetailsState extends State<ConversationDetails> {
},
childCount: attachmentsForChat.length,
),
)
),
SliverToBoxAdapter(child: Container(height: 50))
],
),
),
Expand Down
13 changes: 11 additions & 2 deletions lib/layouts/conversation_list/conversation_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -256,14 +256,16 @@ class _ConversationListState extends State<ConversationList> {
color: Theme.of(context).accentColor,
onSelected: (value) {
if (value == 0) {
ChatBloc().markAllAsRead();
} else if (value == 1) {
Navigator.of(context).push(
ThemeSwitcher.buildPageRoute(
builder: (context) => ConversationList(
showArchivedChats: true,
),
),
);
} else if (value == 1) {
} else if (value == 2) {
Navigator.of(context).push(
ThemeSwitcher.buildPageRoute(
builder: (BuildContext context) {
Expand All @@ -278,12 +280,19 @@ class _ConversationListState extends State<ConversationList> {
PopupMenuItem(
value: 0,
child: Text(
'Archived',
'Mark all as read',
style: Theme.of(context).textTheme.bodyText1,
),
),
PopupMenuItem(
value: 1,
child: Text(
'Archived',
style: Theme.of(context).textTheme.bodyText1,
),
),
PopupMenuItem(
value: 2,
child: Text(
'Settings',
style: Theme.of(context).textTheme.bodyText1,
Expand Down
7 changes: 6 additions & 1 deletion lib/layouts/conversation_view/camera_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:bluebubbles/managers/method_channel_interface.dart';
import 'package:bluebubbles/managers/settings_manager.dart';
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class CameraWidget extends StatefulWidget {
final Function addAttachment;
Expand Down Expand Up @@ -140,6 +141,8 @@ class _CameraWidgetState extends State<CameraWidget> with WidgetsBindingObserver
child: FlatButton(
color: Colors.transparent,
onPressed: () async {
HapticFeedback.mediumImpact();

XFile savedImage = await controller.takePicture();
File file = new File(savedImage.path);

Expand Down Expand Up @@ -177,6 +180,7 @@ class _CameraWidgetState extends State<CameraWidget> with WidgetsBindingObserver
minWidth: 30,
color: Colors.transparent,
onPressed: () async {
HapticFeedback.lightImpact();
await this.openFullCamera(type: 'camera');
},
child: Icon(
Expand All @@ -198,6 +202,7 @@ class _CameraWidgetState extends State<CameraWidget> with WidgetsBindingObserver
minWidth: 30,
color: Colors.transparent,
onPressed: () async {
HapticFeedback.lightImpact();
await this.openFullCamera(type: 'video');
},
child: Icon(
Expand All @@ -219,8 +224,8 @@ class _CameraWidgetState extends State<CameraWidget> with WidgetsBindingObserver
onPressed: () async {
if (BlueBubblesTextField.of(context) == null) return;

HapticFeedback.lightImpact();
BlueBubblesTextField.of(context).cameraIndex = (BlueBubblesTextField.of(context).cameraIndex - 1).abs();

await BlueBubblesTextField.of(context).initializeCameraController();
if (this.mounted) setState(() {});
},
Expand Down
5 changes: 3 additions & 2 deletions lib/layouts/conversation_view/conversation_view_mixin.dart
Original file line number Diff line number Diff line change
Expand Up @@ -264,8 +264,9 @@ mixin ConversationViewMixin<ConversationViewState extends StatefulWidget> on Sta
Widget buildCupertinoTrailing() {
Color fontColor = Theme.of(context).textTheme.headline1.color;
bool manualMark = SettingsManager().settings.enablePrivateAPI && SettingsManager().settings.privateManualMarkAsRead;
bool showManual = !SettingsManager().settings.privateMarkChatAsRead && !widget.chat.isGroup();
List<Widget> items = [
if (manualMark && markingAsRead)
if (showManual && manualMark && markingAsRead)
Padding(
padding: EdgeInsets.only(right: SettingsManager().settings.colorblindMode ? 15.0 : 10.0),
child: Theme(
Expand All @@ -276,7 +277,7 @@ mixin ConversationViewMixin<ConversationViewState extends StatefulWidget> on Sta
radius: 12,
),
)),
if (manualMark && !markingAsRead)
if (showManual && manualMark && !markingAsRead)
Padding(
padding: EdgeInsets.only(right: SettingsManager().settings.colorblindMode ? 10.0 : 5.0),
child: GestureDetector(
Expand Down
Loading

0 comments on commit e6e84b9

Please sign in to comment.