chore: New example

This commit is contained in:
Christian Pauly 2020-11-11 13:22:49 +01:00
parent c8d5bbfd14
commit 01cc650454
1 changed files with 155 additions and 179 deletions

View File

@ -1,17 +1,34 @@
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() { void main() {
runApp(FamedlySdkExampleApp()); runApp(FamedlySdkExampleApp());
} }
class FamedlySdkExampleApp extends StatelessWidget { class FamedlySdkExampleApp extends StatelessWidget {
static Client client = Client('Famedly SDK Example Client', debug: true);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp( return Provider<Client>(
title: 'Famedly SDK Example App', create: (_) => Client('Famedly SDK Example App'),
home: LoginView(), child: Builder(
builder: (context) => MaterialApp(
title: 'Famedly SDK Example App',
home: StreamBuilder<LoginState>(
stream: Provider.of<Client>(context).onLoginStateChanged.stream,
builder:
(BuildContext context, AsyncSnapshot<LoginState> snapshot) {
if (snapshot.hasError) {
return Center(child: Text(snapshot.error.toString()));
}
if (snapshot.data == LoginState.logged) {
return ChatListView();
}
return LoginView();
},
),
),
),
); );
} }
} }
@ -22,80 +39,78 @@ class LoginView extends StatefulWidget {
} }
class _LoginViewState extends State<LoginView> { class _LoginViewState extends State<LoginView> {
final TextEditingController _homeserverController = TextEditingController(); final TextEditingController _usernameController = TextEditingController(),
final TextEditingController _usernameController = TextEditingController(); _passwordController = TextEditingController(),
final TextEditingController _passwordController = TextEditingController(); _domainController = TextEditingController();
bool _isLoading = false;
String _error;
void _loginAction() async { String _errorText;
setState(() => _isLoading = true);
setState(() => _error = null); bool _isLoading = false;
void _loginAction(Client client) async {
setState(() {
_errorText = null;
_isLoading = true;
});
try { try {
if (await FamedlySdkExampleApp.client await client.checkHomeserver(_domainController.text);
.checkServer(_homeserverController.text) == await client.login(
false) { user: _usernameController.text,
throw (Exception('Server not supported')); password: _passwordController.text,
}
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) { } catch (e) {
setState(() => _error = e.toString()); setState(() => _errorText = e.toString());
} }
setState(() => _isLoading = false); setState(() => _isLoading = false);
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final client = Provider.of<Client>(context);
return Scaffold( return Scaffold(
appBar: AppBar(title: Text('Login')), appBar: AppBar(
title: Text('Famedly SDK Example App'),
),
body: ListView( body: ListView(
padding: const EdgeInsets.all(16), padding: EdgeInsets.all(16),
children: [ children: [
TextField(
controller: _homeserverController,
readOnly: _isLoading,
autocorrect: false,
decoration: InputDecoration(
labelText: 'Homeserver',
hintText: 'https://matrix.org',
),
),
SizedBox(height: 8),
TextField( TextField(
controller: _usernameController, controller: _usernameController,
readOnly: _isLoading, readOnly: _isLoading,
autocorrect: false, autocorrect: false,
decoration: InputDecoration( decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Username', labelText: 'Username',
hintText: '@username:domain',
), ),
), ),
SizedBox(height: 8), SizedBox(height: 16),
TextField( TextField(
controller: _passwordController, controller: _passwordController,
readOnly: _isLoading,
autocorrect: false,
obscureText: true, obscureText: true,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Password',
),
),
SizedBox(height: 16),
TextField(
controller: _domainController,
readOnly: _isLoading, readOnly: _isLoading,
autocorrect: false, autocorrect: false,
decoration: InputDecoration( decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Password', labelText: 'Password',
hintText: '****', hintText: 'https://matrix.org',
errorText: _error, errorText: _errorText,
errorMaxLines: 4,
), ),
), ),
SizedBox(height: 8), SizedBox(height: 16),
RaisedButton( RaisedButton(
child: _isLoading ? LinearProgressIndicator() : Text('Login'), child: _isLoading ? LinearProgressIndicator() : Text('Login'),
onPressed: _isLoading ? null : _loginAction, onPressed: _isLoading ? null : () => _loginAction(client),
), ),
], ],
), ),
@ -103,162 +118,123 @@ class _LoginViewState extends State<LoginView> {
} }
} }
class ChatListView extends StatefulWidget { class ChatListView extends StatelessWidget {
@override
_ChatListViewState createState() => _ChatListViewState();
}
class _ChatListViewState extends State<ChatListView> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final client = Provider.of<Client>(context);
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text('Chats'), title: Text('Chats'),
), ),
body: StreamBuilder( body: StreamBuilder(
stream: FamedlySdkExampleApp.client.onSync.stream, stream: client.onSync.stream,
builder: (c, s) => ListView.builder( builder: (context, _) => ListView.builder(
itemCount: FamedlySdkExampleApp.client.rooms.length, itemCount: client.rooms.length,
itemBuilder: (BuildContext context, int i) { itemBuilder: (BuildContext context, int i) => ListTile(
final room = FamedlySdkExampleApp.client.rooms[i]; leading: CircleAvatar(
return ListTile( backgroundImage: client.rooms[i].avatar == null
title: Text(room.displayname + ' (${room.notificationCount})'), ? null
subtitle: Text(room.lastMessage, maxLines: 1), : NetworkImage(
leading: CircleAvatar( client.rooms[i].avatar.getThumbnail(
backgroundImage: NetworkImage(room.avatar.getThumbnail( client,
FamedlySdkExampleApp.client, width: 64,
width: 64, height: 64,
height: 64, ),
)), ),
),
title: Text(client.rooms[i].displayname),
subtitle: Text(client.rooms[i].lastMessage),
onTap: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => ChatView(roomId: client.rooms[i].id),
), ),
onTap: () => Navigator.of(context).push( ),
MaterialPageRoute( ),
builder: (_) => ChatView(room: room),
),
),
);
},
), ),
), ),
); );
} }
} }
class ChatView extends StatefulWidget { class ChatView extends StatelessWidget {
final Room room; final String roomId;
const ChatView({Key key, @required this.room}) : super(key: key); const ChatView({Key key, @required this.roomId}) : super(key: key);
@override
_ChatViewState createState() => _ChatViewState();
}
class _ChatViewState extends State<ChatView> {
final TextEditingController _controller = TextEditingController();
void _sendAction() {
print('Send Text');
widget.room.sendTextEvent(_controller.text);
_controller.clear();
}
Timeline timeline;
Future<bool> getTimeline() async {
timeline ??=
await widget.room.getTimeline(onUpdate: () => setState(() => null));
return true;
}
@override
void dispose() {
timeline?.cancelSubscriptions();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( final client = Provider.of<Client>(context);
appBar: AppBar( final TextEditingController _sendController = TextEditingController();
title: StreamBuilder<Object>( return StreamBuilder<Object>(
stream: widget.room.onUpdate.stream, stream: client.onSync.stream,
builder: (context, snapshot) { builder: (context, _) {
return Text(widget.room.displayname); final room = client.getRoomById(roomId);
}), return Scaffold(
), appBar: AppBar(
body: Column( title: Text(room.displayname),
children: [ ),
Expanded( body: SafeArea(
child: FutureBuilder( child: FutureBuilder<Timeline>(
future: getTimeline(), future: room.getTimeline(),
builder: (context, snapshot) => !snapshot.hasData builder:
? Center( (BuildContext context, AsyncSnapshot<Timeline> snapshot) {
child: CircularProgressIndicator(), if (!snapshot.hasData) {
) return Center(child: CircularProgressIndicator());
: ListView.builder( }
reverse: true, final timeline = snapshot.data;
itemCount: timeline.events.length, return Column(
itemBuilder: (BuildContext context, int i) => Opacity( children: [
opacity: timeline.events[i].status != 2 ? 0.5 : 1, Expanded(
child: ListTile( child: ListView.builder(
title: Row( reverse: true,
children: [ itemCount: timeline.events.length,
Expanded( itemBuilder: (BuildContext context, int i) {
child: Text( final event = timeline.events[i];
timeline.events[i].sender.calcDisplayname(), final sender = event.sender;
), return ListTile(
), leading: CircleAvatar(
Text( backgroundImage: sender.avatarUrl == null
timeline.events[i].originServerTs ? null
.toIso8601String(), : NetworkImage(
style: TextStyle(fontSize: 12), sender.avatarUrl.getThumbnail(
), client,
],
),
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, width: 64,
height: 64, height: 64,
), ),
) ),
: null, ),
), title: Text(sender.calcDisplayname()),
subtitle: Text(event.body),
);
},
), ),
), ),
), Divider(height: 1),
Container(
height: 56,
child: Row(
children: [
Expanded(
child: TextField(
controller: _sendController,
),
),
IconButton(
icon: Icon(Icons.send),
onPressed: () {
room.sendTextEvent(_sendController.text);
_sendController.clear();
},
),
],
),
),
],
);
},
),
), ),
), );
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,
)
],
),
),
],
),
);
} }
} }