import 'package:famedlysdk/famedlysdk.dart'; import 'package:flutter/material.dart'; void main() { runApp(FamedlySdkExampleApp()); } class FamedlySdkExampleApp extends StatelessWidget { static Client client = Client('Famedly SDK Example Client', debug: true); @override Widget build(BuildContext context) { return MaterialApp( title: 'Famedly SDK Example App', home: LoginView(), ); } } class LoginView extends StatefulWidget { @override _LoginViewState createState() => _LoginViewState(); } class _LoginViewState extends State { final TextEditingController _homeserverController = TextEditingController(); final TextEditingController _usernameController = TextEditingController(); final TextEditingController _passwordController = TextEditingController(); bool _isLoading = false; String _error; void _loginAction() async { setState(() => _isLoading = true); setState(() => _error = null); try { if (await FamedlySdkExampleApp.client .checkServer(_homeserverController.text) == false) { throw (Exception('Server not supported')); } if (await FamedlySdkExampleApp.client.login( _usernameController.text, _passwordController.text, ) == false) { throw (Exception('Username or password incorrect')); } Navigator.of(context).pushAndRemoveUntil( MaterialPageRoute(builder: (_) => ChatListView()), (route) => false, ); } catch (e) { setState(() => _error = e.toString()); } setState(() => _isLoading = false); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Login')), body: ListView( padding: const EdgeInsets.all(16), children: [ TextField( controller: _homeserverController, readOnly: _isLoading, autocorrect: false, decoration: InputDecoration( labelText: 'Homeserver', hintText: 'https://matrix.org', ), ), SizedBox(height: 8), TextField( controller: _usernameController, readOnly: _isLoading, autocorrect: false, decoration: InputDecoration( labelText: 'Username', hintText: '@username:domain', ), ), SizedBox(height: 8), TextField( controller: _passwordController, obscureText: true, readOnly: _isLoading, autocorrect: false, decoration: InputDecoration( labelText: 'Password', hintText: '****', errorText: _error, ), ), SizedBox(height: 8), RaisedButton( child: _isLoading ? LinearProgressIndicator() : Text('Login'), onPressed: _isLoading ? null : _loginAction, ), ], ), ); } } class ChatListView extends StatefulWidget { @override _ChatListViewState createState() => _ChatListViewState(); } class _ChatListViewState extends State { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Chats'), ), body: StreamBuilder( stream: FamedlySdkExampleApp.client.onSync.stream, builder: (c, s) => ListView.builder( itemCount: FamedlySdkExampleApp.client.rooms.length, itemBuilder: (BuildContext context, int i) { final room = FamedlySdkExampleApp.client.rooms[i]; return ListTile( title: Text(room.displayname + ' (${room.notificationCount})'), subtitle: Text(room.lastMessage, maxLines: 1), leading: CircleAvatar( backgroundImage: NetworkImage(room.avatar.getThumbnail( FamedlySdkExampleApp.client, width: 64, height: 64, )), ), onTap: () => Navigator.of(context).push( MaterialPageRoute( builder: (_) => ChatView(room: room), ), ), ); }, ), ), ); } } class ChatView extends StatefulWidget { final Room room; const ChatView({Key key, @required this.room}) : super(key: key); @override _ChatViewState createState() => _ChatViewState(); } class _ChatViewState extends State { final TextEditingController _controller = TextEditingController(); void _sendAction() { print('Send Text'); widget.room.sendTextEvent(_controller.text); _controller.clear(); } Timeline timeline; Future getTimeline() async { timeline ??= await widget.room.getTimeline(onUpdate: () => setState(() => null)); return true; } @override void dispose() { timeline?.cancelSubscriptions(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: StreamBuilder( stream: widget.room.onUpdate.stream, builder: (context, snapshot) { return Text(widget.room.displayname); }), ), body: Column( children: [ Expanded( child: FutureBuilder( future: getTimeline(), builder: (context, snapshot) => !snapshot.hasData ? Center( child: CircularProgressIndicator(), ) : ListView.builder( reverse: true, itemCount: timeline.events.length, itemBuilder: (BuildContext context, int i) => Opacity( opacity: timeline.events[i].status != 2 ? 0.5 : 1, child: ListTile( title: Row( children: [ Expanded( child: Text( timeline.events[i].sender.calcDisplayname(), ), ), Text( timeline.events[i].originServerTs .toIso8601String(), style: TextStyle(fontSize: 12), ), ], ), subtitle: Text(timeline.events[i].body), leading: CircleAvatar( child: timeline.events[i].sender?.avatarUrl == null ? Icon(Icons.person) : null, backgroundImage: timeline.events[i].sender?.avatarUrl != null ? NetworkImage( timeline.events[i].sender?.avatarUrl ?.getThumbnail( FamedlySdkExampleApp.client, width: 64, height: 64, ), ) : null, ), ), ), ), ), ), Container( height: 60, child: Row( children: [ Expanded( child: TextField( controller: _controller, decoration: InputDecoration( contentPadding: const EdgeInsets.symmetric(horizontal: 8), labelText: 'Send a message ...', ), ), ), IconButton( icon: Icon(Icons.send), onPressed: _sendAction, ) ], ), ), ], ), ); } }