ui: Make the bubbles and conversations update their timestamp
I'm not proud of this one but it works. BUT I WILL REPLACE IT AS SOON AS I FIND A BETTER SOLUTION!
This commit is contained in:
parent
5ead5fb230
commit
764b63613a
@ -1,3 +1,4 @@
|
|||||||
|
import "dart:async";
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:moxxyv2/ui/widgets/topbar.dart';
|
import 'package:moxxyv2/ui/widgets/topbar.dart';
|
||||||
import 'package:moxxyv2/ui/widgets/chatbubble.dart';
|
import 'package:moxxyv2/ui/widgets/chatbubble.dart';
|
||||||
@ -37,7 +38,6 @@ PopupMenuItem popupItemWithIcon(dynamic value, String text, IconData icon) {
|
|||||||
// TODO: Maybe use a PageView to combine ConversationsPage and ConversationPage
|
// TODO: Maybe use a PageView to combine ConversationsPage and ConversationPage
|
||||||
|
|
||||||
class _MessageListViewModel {
|
class _MessageListViewModel {
|
||||||
final List<Message> messages;
|
|
||||||
final Conversation conversation;
|
final Conversation conversation;
|
||||||
final SendMessageFunction sendMessage;
|
final SendMessageFunction sendMessage;
|
||||||
final void Function(bool showSendButton) setShowSendButton;
|
final void Function(bool showSendButton) setShowSendButton;
|
||||||
@ -45,7 +45,81 @@ class _MessageListViewModel {
|
|||||||
final void Function(bool scrollToEndButton) setShowScrollToEndButton;
|
final void Function(bool scrollToEndButton) setShowScrollToEndButton;
|
||||||
final bool showScrollToEndButton;
|
final bool showScrollToEndButton;
|
||||||
|
|
||||||
_MessageListViewModel({ required this.conversation, required this.messages, required this.showSendButton, required this.sendMessage, required this.setShowSendButton, required this.showScrollToEndButton, required this.setShowScrollToEndButton });
|
_MessageListViewModel({ required this.conversation, required this.showSendButton, required this.sendMessage, required this.setShowSendButton, required this.showScrollToEndButton, required this.setShowScrollToEndButton });
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ListViewWrapperViewModel {
|
||||||
|
final List<Message> messages;
|
||||||
|
|
||||||
|
_ListViewWrapperViewModel({ required this.messages });
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Q: Why wrap the ListView? A: So we can update it every minute to update the timestamps
|
||||||
|
// TODO: Replace with something better
|
||||||
|
class _ListViewWrapperState extends State<ListViewWrapper> {
|
||||||
|
final double maxWidth;
|
||||||
|
final String jid;
|
||||||
|
Timer? _updateTimer;
|
||||||
|
int _tickCounter = 0;
|
||||||
|
|
||||||
|
_ListViewWrapperState({ required this.maxWidth, required this.jid }) {
|
||||||
|
this._updateTimer = Timer.periodic(Duration(minutes: 1), this._timerCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _timerCallback(Timer timer) {
|
||||||
|
setState(() {
|
||||||
|
this._tickCounter++;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _renderBubble(List<Message> messages, int index, double maxWidth) {
|
||||||
|
Message item = messages[index];
|
||||||
|
// TODO
|
||||||
|
bool start = index - 1 < 0 ? true : messages[index - 1].sent != item.sent;
|
||||||
|
bool end = index + 1 >= messages.length ? true : messages[index + 1].sent != item.sent;
|
||||||
|
bool between = !start && !end;
|
||||||
|
return ChatBubble(
|
||||||
|
messageContent: item.body,
|
||||||
|
timestamp: item.timestamp,
|
||||||
|
sentBySelf: true,
|
||||||
|
start: start,
|
||||||
|
end: end,
|
||||||
|
between: between,
|
||||||
|
closerTogether: !end,
|
||||||
|
maxWidth: maxWidth
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
if (this._updateTimer != null) {
|
||||||
|
this._updateTimer!.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext build) {
|
||||||
|
return StoreConnector<MoxxyState, _ListViewWrapperViewModel>(
|
||||||
|
converter: (store) => _ListViewWrapperViewModel(
|
||||||
|
messages: store.state.messages.containsKey(this.jid) ? store.state.messages[this.jid]! : [],
|
||||||
|
),
|
||||||
|
builder: (context, viewModel) => ListView.builder(
|
||||||
|
itemCount: viewModel.messages.length,
|
||||||
|
itemBuilder: (context, index) => this._renderBubble(viewModel.messages, index, maxWidth)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ListViewWrapper extends StatefulWidget {
|
||||||
|
final double maxWidth;
|
||||||
|
final String jid;
|
||||||
|
|
||||||
|
ListViewWrapper({ required this.maxWidth, required this.jid });
|
||||||
|
|
||||||
|
@override
|
||||||
|
_ListViewWrapperState createState() => _ListViewWrapperState(maxWidth: this.maxWidth, jid: this.jid);
|
||||||
}
|
}
|
||||||
|
|
||||||
class ConversationPage extends StatelessWidget {
|
class ConversationPage extends StatelessWidget {
|
||||||
@ -82,24 +156,6 @@ class ConversationPage extends StatelessWidget {
|
|||||||
this._onMessageTextChanged("", viewModel);
|
this._onMessageTextChanged("", viewModel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _renderBubble(List<Message> messages, int index, double maxWidth) {
|
|
||||||
Message item = messages[index];
|
|
||||||
// TODO
|
|
||||||
bool start = index - 1 < 0 ? true : messages[index - 1].sent != item.sent;
|
|
||||||
bool end = index + 1 >= messages.length ? true : messages[index + 1].sent != item.sent;
|
|
||||||
bool between = !start && !end;
|
|
||||||
return ChatBubble(
|
|
||||||
messageContent: item.body,
|
|
||||||
timestamp: item.timestamp,
|
|
||||||
sentBySelf: true,
|
|
||||||
start: start,
|
|
||||||
end: end,
|
|
||||||
between: between,
|
|
||||||
closerTogether: !end,
|
|
||||||
maxWidth: maxWidth
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -109,7 +165,6 @@ class ConversationPage extends StatelessWidget {
|
|||||||
|
|
||||||
return StoreConnector<MoxxyState, _MessageListViewModel>(
|
return StoreConnector<MoxxyState, _MessageListViewModel>(
|
||||||
converter: (store) => _MessageListViewModel(
|
converter: (store) => _MessageListViewModel(
|
||||||
messages: store.state.messages.containsKey(jid) ? store.state.messages[jid]! : [],
|
|
||||||
conversation: store.state.conversations.firstWhere((item) => item.jid == jid),
|
conversation: store.state.conversations.firstWhere((item) => item.jid == jid),
|
||||||
showSendButton: store.state.conversationPageState.showSendButton,
|
showSendButton: store.state.conversationPageState.showSendButton,
|
||||||
setShowSendButton: (show) => store.dispatch(SetShowSendButtonAction(show: show)),
|
setShowSendButton: (show) => store.dispatch(SetShowSendButtonAction(show: show)),
|
||||||
@ -172,10 +227,7 @@ class ConversationPage extends StatelessWidget {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
ListView.builder(
|
ListViewWrapper(maxWidth: maxWidth, jid: jid),
|
||||||
itemCount: viewModel.messages.length,
|
|
||||||
itemBuilder: (context, index) => this._renderBubble(viewModel.messages, index, maxWidth)
|
|
||||||
),
|
|
||||||
Positioned(
|
Positioned(
|
||||||
bottom: 64.0,
|
bottom: 64.0,
|
||||||
right: 16.0,
|
right: 16.0,
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import "dart:async";
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:moxxyv2/ui/widgets/topbar.dart';
|
import 'package:moxxyv2/ui/widgets/topbar.dart';
|
||||||
import 'package:moxxyv2/ui/widgets/conversation.dart';
|
import 'package:moxxyv2/ui/widgets/conversation.dart';
|
||||||
@ -13,6 +14,68 @@ import 'package:flutter_speed_dial/flutter_speed_dial.dart';
|
|||||||
import 'package:flutter_redux/flutter_redux.dart';
|
import 'package:flutter_redux/flutter_redux.dart';
|
||||||
import 'package:redux/redux.dart';
|
import 'package:redux/redux.dart';
|
||||||
|
|
||||||
|
class _ListViewWrapperViewModel {
|
||||||
|
final List<Conversation> conversations;
|
||||||
|
|
||||||
|
_ListViewWrapperViewModel({ required this.conversations });
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Q: Why wrap the ListView? A: So we can update it every minute to update the timestamps
|
||||||
|
// TODO: Replace with something better
|
||||||
|
class _ListViewWrapperState extends State<ListViewWrapper> {
|
||||||
|
Timer? _updateTimer;
|
||||||
|
int _tickCounter = 0;
|
||||||
|
|
||||||
|
_ListViewWrapperState() {
|
||||||
|
this._updateTimer = Timer.periodic(Duration(minutes: 1), this._timerCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _timerCallback(Timer timer) {
|
||||||
|
print("TOCK");
|
||||||
|
setState(() {
|
||||||
|
this._tickCounter++;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
if (this._updateTimer != null) {
|
||||||
|
this._updateTimer!.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext build) {
|
||||||
|
return StoreConnector<MoxxyState, _ListViewWrapperViewModel>(
|
||||||
|
converter: (store) => _ListViewWrapperViewModel(
|
||||||
|
conversations: store.state.conversations
|
||||||
|
),
|
||||||
|
builder: (context, viewModel) {
|
||||||
|
double maxTextWidth = MediaQuery.of(context).size.width * 0.6;
|
||||||
|
|
||||||
|
return ListView.builder(
|
||||||
|
itemCount: viewModel.conversations.length,
|
||||||
|
itemBuilder: (_context, index) {
|
||||||
|
Conversation item = viewModel.conversations[index];
|
||||||
|
return InkWell(
|
||||||
|
onTap: () => Navigator.pushNamed(context, "/conversation", arguments: ConversationPageArguments(jid: item.jid)),
|
||||||
|
child: ConversationsListRow(item.avatarUrl, item.title, item.lastMessageBody, item.unreadCounter, maxTextWidth, item.lastChangeTimestamp)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ListViewWrapper extends StatefulWidget {
|
||||||
|
ListViewWrapper();
|
||||||
|
|
||||||
|
@override
|
||||||
|
_ListViewWrapperState createState() => _ListViewWrapperState();
|
||||||
|
}
|
||||||
|
|
||||||
class _ConversationsListViewModel {
|
class _ConversationsListViewModel {
|
||||||
final List<Conversation> conversations;
|
final List<Conversation> conversations;
|
||||||
final String displayName;
|
final String displayName;
|
||||||
@ -27,19 +90,8 @@ enum ConversationsOptions {
|
|||||||
|
|
||||||
class ConversationsPage extends StatelessWidget {
|
class ConversationsPage extends StatelessWidget {
|
||||||
Widget _listWrapper(BuildContext context, _ConversationsListViewModel viewModel) {
|
Widget _listWrapper(BuildContext context, _ConversationsListViewModel viewModel) {
|
||||||
double maxTextWidth = MediaQuery.of(context).size.width * 0.6;
|
|
||||||
|
|
||||||
if (viewModel.conversations.length > 0) {
|
if (viewModel.conversations.length > 0) {
|
||||||
return ListView.builder(
|
return ListViewWrapper();
|
||||||
itemCount: viewModel.conversations.length,
|
|
||||||
itemBuilder: (_context, index) {
|
|
||||||
Conversation item = viewModel.conversations[index];
|
|
||||||
return InkWell(
|
|
||||||
onTap: () => Navigator.pushNamed(context, "/conversation", arguments: ConversationPageArguments(jid: item.jid)),
|
|
||||||
child: ConversationsListRow(item.avatarUrl, item.title, item.lastMessageBody, item.unreadCounter, maxTextWidth, item.lastChangeTimestamp)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
|
Loading…
Reference in New Issue
Block a user