Seperate personal and public chats

Also add unused (for now) calls bottom navigation icon.
parent d221ce3b
......@@ -25,9 +25,26 @@ import 'package:pattle/src/ui/main/sync_bloc.dart';
final bloc = ChatOverviewBloc();
class ChatOverviewBloc {
PublishSubject<List<ChatOverview>> _chatsSubj =
PublishSubject<List<ChatOverview>>();
Observable<List<ChatOverview>> get chats => _chatsSubj.stream;
final _chatsSubj = PublishSubject<List<ChatOverview>>();
Observable<List<ChatOverview>> get personalChats =>
_chatsSubj.stream.flatMapIterable(
(list) => Stream.value([
list
.where((chat) =>
chat.room.aliases == null || chat.room.aliases.isEmpty)
.toList()
]),
);
Observable<List<ChatOverview>> get publicChats =>
_chatsSubj.stream.flatMapIterable(
(list) => Stream.value([
list
.where((chat) =>
chat.room.aliases != null && chat.room.aliases.isNotEmpty)
.toList(),
]),
);
final LocalUser _user = di.getLocalUser();
......
......@@ -16,22 +16,30 @@
// along with Pattle. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:mdi/mdi.dart';
import 'package:pattle/src/app.dart';
import 'package:pattle/src/ui/main/overview/models/chat_overview.dart';
import 'package:pattle/src/ui/main/overview/chat_overview_bloc.dart';
import 'package:pattle/src/ui/main/widgets/chat_name.dart';
import 'package:pattle/src/ui/main/overview/widgets/chat_overview_list.dart';
import 'package:pattle/src/ui/main/widgets/error.dart';
import 'package:pattle/src/ui/resources/localizations.dart';
import 'package:pattle/src/ui/resources/theme.dart';
import 'package:pattle/src/ui/util/date_format.dart';
import 'package:pattle/src/ui/util/matrix_image.dart';
import 'package:pattle/src/ui/util/room.dart';
import 'package:pattle/src/ui/util/user.dart';
import 'package:transparent_image/transparent_image.dart';
import 'widgets/subtitle.dart';
class ChatOverviewPageState extends State<ChatOverviewPage> {
int _currentTab = 0;
final personalTab = ChatOverviewList(chats: bloc.personalChats);
final publicTab = ChatOverviewList(chats: bloc.publicChats);
void _switchTabTo(int index) {
// Temporary: Don't do anything for the calls tab
if (index > 1) {
return;
}
setState(() {
_currentTab = index;
});
}
void goToCreateGroup() {
Navigator.of(context).pushNamed(Routes.chatsNew);
}
......@@ -64,7 +72,15 @@ class ChatOverviewPageState extends State<ChatOverviewPage> {
children: <Widget>[
ErrorBanner(),
Expanded(
child: Scrollbar(child: _buildOverviewList()),
child: AnimatedCrossFade(
duration: const Duration(milliseconds: 200),
firstChild: personalTab,
secondChild: publicTab,
crossFadeState: _currentTab == 0
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
alignment: Alignment.center,
),
)
],
),
......@@ -72,107 +88,24 @@ class ChatOverviewPageState extends State<ChatOverviewPage> {
onPressed: goToCreateGroup,
child: Icon(Icons.chat),
),
);
}
Widget _buildOverviewList() {
return StreamBuilder<List<ChatOverview>>(
stream: bloc.chats,
builder: (
BuildContext context,
AsyncSnapshot<List<ChatOverview>> snapshot,
) {
Widget widget;
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
widget = Center(child: CircularProgressIndicator());
break;
case ConnectionState.active:
case ConnectionState.done:
final chats = snapshot.data;
if (chats == null || chats.isEmpty) {
return Center(child: CircularProgressIndicator());
}
widget = ListView.separated(
separatorBuilder: (context, index) => Divider(
height: 1,
indent: 64,
),
itemCount: chats.length,
itemBuilder: (context, index) {
return _buildChatOverview(chats[index]);
},
);
break;
}
return widget;
},
);
}
Widget _buildChatOverview(ChatOverview chat) {
var time = formatAsListItem(context, chat.latestEvent?.time);
// Avatar
final avatarUrl = avatarUrlOf(chat.room);
var avatar;
if (avatarUrl != null) {
avatar = Hero(
tag: chat.room.id,
child: Container(
width: 48,
height: 48,
child: ClipOval(
child: FadeInImage(
fit: BoxFit.cover,
placeholder: MemoryImage(kTransparentImage),
image: MatrixImage(avatarUrl, width: 64, height: 64),
),
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(
icon: Icon(Icons.chat_bubble),
title: Text(l(context).personal),
),
),
);
} else {
avatar = CircleAvatar(
foregroundColor: Colors.white,
backgroundColor: chat.room.isDirect
? colorOf(context, chat.room.directUser)
: LightColors.red[500],
radius: 24,
child: Icon(chat.room.isDirect ? Icons.person : Icons.group),
);
}
return ListTile(
title: Row(
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
children: <Widget>[
Expanded(
child: ChatName(
room: chat.room,
),
),
Text(
time,
style: Theme.of(context).textTheme.subtitle.copyWith(
fontWeight: FontWeight.normal,
color: Theme.of(context).textTheme.caption.color,
),
BottomNavigationBarItem(
icon: Icon(Mdi.bullhorn),
title: Text(l(context).public),
),
BottomNavigationBarItem(
icon: Icon(Icons.phone),
title: Text(l(context).calls),
)
],
currentIndex: _currentTab,
onTap: _switchTabTo,
),
dense: false,
onTap: () {
Navigator.pushNamed(context, Routes.chats, arguments: chat.room);
},
leading: avatar,
contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 4),
subtitle: Subtitle.forChat(chat),
);
}
}
......
......@@ -46,6 +46,9 @@ class Strings {
final participants = 'Participants';
final profile = 'Profile';
final settings = 'Settings';
final personal = 'Personal';
final public = 'Public';
final calls = 'Calls';
final description = 'Description';
final noDescriptionSet = 'No description has been set';
......
......@@ -228,6 +228,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.19.0"
mdi:
dependency: "direct main"
description:
name: mdi
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.1"
meta:
dependency: transitive
description:
......
......@@ -52,6 +52,8 @@ dependencies:
shared_preferences: ^0.5.3+4
mdi: ^0.2.1
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.2
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment