Compare commits
No commits in common. "e4785525876d9e70d5648a3deacd9f374b095afd" and "799c15321b1deac7443089792207f58e1ac7972b" have entirely different histories.
e478552587
...
799c15321b
|
@ -23,8 +23,6 @@ linter:
|
||||||
rules:
|
rules:
|
||||||
# avoid_print: false # Uncomment to disable the `avoid_print` rule
|
# avoid_print: false # Uncomment to disable the `avoid_print` rule
|
||||||
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
|
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
|
||||||
curly_braces_in_flow_control_structures: false
|
|
||||||
avoid_print: false
|
|
||||||
|
|
||||||
# Additional information about this file can be found at
|
# Additional information about this file can be found at
|
||||||
# https://dart.dev/guides/language/analysis-options
|
# https://dart.dev/guides/language/analysis-options
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:label="zenith"
|
android:label="zenith"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
|
|
57
lib/chats.dart
Normal file
57
lib/chats.dart
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:matrix/matrix.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'package:zenith/zenith_client_provider.dart';
|
||||||
|
|
||||||
|
class ChatsPage extends StatefulWidget {
|
||||||
|
const ChatsPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ChatsPage> createState() => _ChatsPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ChatsPageState extends State<ChatsPage> {
|
||||||
|
final serverController = TextEditingController();
|
||||||
|
final usernameController = TextEditingController();
|
||||||
|
final passwordController = TextEditingController();
|
||||||
|
late Client client;
|
||||||
|
bool roomsLoading = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
client = Provider.of<ZenithClientProvider>(context, listen: false).client;
|
||||||
|
client.onRoomState.stream.listen((event) {
|
||||||
|
print(event.type);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendMessage() {}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
||||||
|
title: const Text("Zenith"),
|
||||||
|
),
|
||||||
|
body: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Center(
|
||||||
|
child: roomsLoading
|
||||||
|
? const CircularProgressIndicator()
|
||||||
|
: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [Text("${client.rooms.length} Rooms.")],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
floatingActionButton: FloatingActionButton(
|
||||||
|
onPressed: sendMessage,
|
||||||
|
tooltip: 'Send message',
|
||||||
|
child: const Icon(Icons.send),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
107
lib/login.dart
107
lib/login.dart
|
@ -1,7 +1,8 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:matrix/matrix.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:zenith/rooms.dart';
|
import 'package:zenith/chats.dart';
|
||||||
import 'package:zenith/zenith_client_provider.dart';
|
import 'package:zenith/zenith_client_provider.dart';
|
||||||
|
|
||||||
class LoginPage extends StatefulWidget {
|
class LoginPage extends StatefulWidget {
|
||||||
|
@ -15,36 +16,11 @@ class _LoginPageState extends State<LoginPage> {
|
||||||
final serverController = TextEditingController();
|
final serverController = TextEditingController();
|
||||||
final usernameController = TextEditingController();
|
final usernameController = TextEditingController();
|
||||||
final passwordController = TextEditingController();
|
final passwordController = TextEditingController();
|
||||||
bool loggingIn = false;
|
|
||||||
String failedMessage = '';
|
|
||||||
|
|
||||||
void connectMatrix() async {
|
void connectMatrix() async {
|
||||||
setState(() {
|
final provider = Provider.of<ZenithClientProvider>(context, listen: false);
|
||||||
loggingIn = true;
|
await provider.initialize(serverController.text, usernameController.text,
|
||||||
});
|
passwordController.text);
|
||||||
|
|
||||||
try {
|
|
||||||
final provider =
|
|
||||||
Provider.of<ZenithClientProvider>(context, listen: false);
|
|
||||||
await provider.initialize(serverController.text, usernameController.text,
|
|
||||||
passwordController.text);
|
|
||||||
} catch (error) {
|
|
||||||
print("Error signing in $error");
|
|
||||||
setState(() {
|
|
||||||
failedMessage = error.toString();
|
|
||||||
});
|
|
||||||
|
|
||||||
Future.delayed(const Duration(seconds: 10), () {
|
|
||||||
setState(() {
|
|
||||||
failedMessage = '';
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
} finally {
|
|
||||||
setState(() {
|
|
||||||
loggingIn = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
final prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
prefs.setString("homeserver", serverController.text);
|
prefs.setString("homeserver", serverController.text);
|
||||||
|
@ -54,7 +30,7 @@ class _LoginPageState extends State<LoginPage> {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
Navigator.pushAndRemoveUntil(
|
Navigator.pushAndRemoveUntil(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(builder: (context) => const RoomsPage()),
|
MaterialPageRoute(builder: (context) => const ChatsPage()),
|
||||||
(route) => false);
|
(route) => false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,47 +41,40 @@ class _LoginPageState extends State<LoginPage> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Consumer<ZenithClientProvider>(
|
return Scaffold(
|
||||||
builder: (context, provider, child) => Scaffold(
|
appBar: AppBar(
|
||||||
appBar: AppBar(
|
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
||||||
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
title: const Text("Login"),
|
||||||
title: const Text("Login"),
|
),
|
||||||
),
|
body: Padding(
|
||||||
body: Padding(
|
padding: const EdgeInsets.all(16.0),
|
||||||
padding: const EdgeInsets.all(16.0),
|
child: Center(
|
||||||
child: Center(
|
child: Column(
|
||||||
child: Column(
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
children: [
|
||||||
children: [
|
TextFormField(
|
||||||
TextFormField(
|
controller: serverController,
|
||||||
controller: serverController,
|
decoration: const InputDecoration(
|
||||||
decoration: const InputDecoration(
|
labelText: 'Server', hintText: 'https://matrix.org'),
|
||||||
labelText: 'Server', hintText: 'https://matrix.org'),
|
),
|
||||||
),
|
TextFormField(
|
||||||
TextFormField(
|
controller: usernameController,
|
||||||
controller: usernameController,
|
decoration: const InputDecoration(
|
||||||
decoration: const InputDecoration(
|
labelText: 'Username', hintText: 'john'),
|
||||||
labelText: 'Username', hintText: 'john'),
|
),
|
||||||
),
|
TextFormField(
|
||||||
TextFormField(
|
controller: passwordController,
|
||||||
controller: passwordController,
|
decoration: const InputDecoration(labelText: 'Password'),
|
||||||
decoration: const InputDecoration(labelText: 'Password'),
|
obscureText: true,
|
||||||
obscureText: true,
|
),
|
||||||
onFieldSubmitted: (value) => connectMatrix(),
|
],
|
||||||
),
|
|
||||||
Text(failedMessage,
|
|
||||||
style: Theme.of(context).textTheme.headlineSmall)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
floatingActionButton: loggingIn
|
),
|
||||||
? const CircularProgressIndicator()
|
floatingActionButton: FloatingActionButton(
|
||||||
: FloatingActionButton(
|
onPressed: connectMatrix,
|
||||||
onPressed: connectMatrix,
|
tooltip: 'Log in',
|
||||||
tooltip: 'Log in',
|
child: const Icon(Icons.login),
|
||||||
child: const Icon(Icons.login),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:matrix/matrix.dart';
|
import 'package:matrix/matrix.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:zenith/rooms.dart';
|
import 'package:zenith/chats.dart';
|
||||||
import 'package:zenith/login.dart';
|
import 'package:zenith/login.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:zenith/zenith_client_provider.dart';
|
import 'package:zenith/zenith_client_provider.dart';
|
||||||
|
@ -66,7 +66,7 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||||
if (!savedCreds) {
|
if (!savedCreds) {
|
||||||
return const LoginPage();
|
return const LoginPage();
|
||||||
} else {
|
} else {
|
||||||
return const RoomsPage();
|
return const ChatsPage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,90 +0,0 @@
|
||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:matrix/matrix.dart';
|
|
||||||
|
|
||||||
class RoomPage extends StatefulWidget {
|
|
||||||
const RoomPage({super.key, required this.room});
|
|
||||||
|
|
||||||
final Room room;
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<RoomPage> createState() => _RoomPageState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _RoomPageState extends State<RoomPage> {
|
|
||||||
Timeline? timeline;
|
|
||||||
final chatController = TextEditingController();
|
|
||||||
StreamSubscription? updateListener;
|
|
||||||
|
|
||||||
void updateTimeline() async {
|
|
||||||
final newTimeline =
|
|
||||||
await widget.room.getTimeline(eventContextId: widget.room.fullyRead);
|
|
||||||
setState(() {
|
|
||||||
timeline = newTimeline;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
updateTimeline();
|
|
||||||
updateListener = widget.room.onUpdate.stream.listen((event) {
|
|
||||||
updateTimeline();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
super.dispose();
|
|
||||||
updateListener?.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
void sendMessage() {}
|
|
||||||
|
|
||||||
List<Widget> getChildren() {
|
|
||||||
if (timeline == null) return [const CircularProgressIndicator()];
|
|
||||||
return [
|
|
||||||
Expanded(
|
|
||||||
child: ListView.builder(
|
|
||||||
itemCount: timeline?.events.length,
|
|
||||||
reverse: true,
|
|
||||||
itemBuilder: (context, index) => ListTile(
|
|
||||||
title: Text(timeline!.events[index].senderFromMemoryOrFallback
|
|
||||||
.displayName ??
|
|
||||||
""),
|
|
||||||
subtitle: Text(timeline!.events[index].body),
|
|
||||||
)),
|
|
||||||
),
|
|
||||||
TextFormField(
|
|
||||||
controller: chatController,
|
|
||||||
decoration: const InputDecoration(hintText: 'Message'),
|
|
||||||
onFieldSubmitted: (value) async {
|
|
||||||
print("Sending text event $value to room ${widget.room.id}...");
|
|
||||||
await widget.room.sendTextEvent(value);
|
|
||||||
chatController.text = '';
|
|
||||||
},
|
|
||||||
),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
|
||||||
title: Text(widget.room.getLocalizedDisplayname()),
|
|
||||||
),
|
|
||||||
body: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Column(
|
|
||||||
children: getChildren(),
|
|
||||||
)),
|
|
||||||
floatingActionButton: FloatingActionButton(
|
|
||||||
onPressed: sendMessage,
|
|
||||||
tooltip: 'Send message',
|
|
||||||
child: const Icon(Icons.send),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
102
lib/rooms.dart
102
lib/rooms.dart
|
@ -1,102 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:matrix/matrix.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
|
||||||
import 'package:zenith/login.dart';
|
|
||||||
import 'package:zenith/room.dart';
|
|
||||||
import 'package:zenith/zenith_client_provider.dart';
|
|
||||||
|
|
||||||
class RoomsPage extends StatefulWidget {
|
|
||||||
const RoomsPage({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<RoomsPage> createState() => _RoomsPageState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _RoomsPageState extends State<RoomsPage> {
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
}
|
|
||||||
|
|
||||||
void sendMessage() {}
|
|
||||||
|
|
||||||
void viewRoom(Room room) {
|
|
||||||
Navigator.push(
|
|
||||||
context, MaterialPageRoute(builder: (context) => RoomPage(room: room)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
|
||||||
title: const Text("Zenith"),
|
|
||||||
actions: [
|
|
||||||
IconButton(
|
|
||||||
onPressed: () {
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => AlertDialog(
|
|
||||||
title: const Text("Log out?"),
|
|
||||||
actions: [
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
},
|
|
||||||
child: const Text("Cancel")),
|
|
||||||
ElevatedButton(
|
|
||||||
child: const Text("Confirm"),
|
|
||||||
onPressed: () async {
|
|
||||||
print("Logging out...");
|
|
||||||
final prefs = await SharedPreferences.getInstance();
|
|
||||||
prefs.remove("homeserver");
|
|
||||||
prefs.remove("username");
|
|
||||||
prefs.remove("password");
|
|
||||||
|
|
||||||
if (!mounted) return;
|
|
||||||
final provider = Provider.of<ZenithClientProvider>(
|
|
||||||
context,
|
|
||||||
listen: false);
|
|
||||||
await provider.client.logout();
|
|
||||||
|
|
||||||
if (!mounted) return;
|
|
||||||
Navigator.pushAndRemoveUntil(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => const LoginPage()),
|
|
||||||
(route) => false);
|
|
||||||
},
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
icon: const Icon(Icons.logout))
|
|
||||||
],
|
|
||||||
),
|
|
||||||
body: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Center(child: Consumer<ZenithClientProvider>(
|
|
||||||
builder: (context, provider, child) {
|
|
||||||
if (provider.loading)
|
|
||||||
return const CircularProgressIndicator();
|
|
||||||
else
|
|
||||||
return ListView.builder(
|
|
||||||
itemCount: provider.client.rooms.length,
|
|
||||||
itemBuilder: (context, index) => ListTile(
|
|
||||||
title: Text(provider.client.rooms[index]
|
|
||||||
.getLocalizedDisplayname()),
|
|
||||||
onTap: () => viewRoom(provider.client.rooms[index]),
|
|
||||||
));
|
|
||||||
},
|
|
||||||
)),
|
|
||||||
),
|
|
||||||
floatingActionButton: FloatingActionButton(
|
|
||||||
onPressed: sendMessage,
|
|
||||||
tooltip: 'Send message',
|
|
||||||
child: const Icon(Icons.send),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,28 +3,23 @@ import 'package:matrix/matrix.dart';
|
||||||
|
|
||||||
class ZenithClientProvider extends ChangeNotifier {
|
class ZenithClientProvider extends ChangeNotifier {
|
||||||
late Client _client;
|
late Client _client;
|
||||||
bool _loading = true;
|
|
||||||
|
|
||||||
Client get client => _client;
|
Client get client => _client;
|
||||||
|
|
||||||
bool get loading => _loading;
|
void setClient(Client newClient) {
|
||||||
|
_client = newClient;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> initialize(
|
Future<void> initialize(
|
||||||
String homeserver, String username, String password) async {
|
String homeserver, String username, String password) async {
|
||||||
_loading = true;
|
|
||||||
_client = Client("zenith");
|
_client = Client("zenith");
|
||||||
try {
|
print("Checking homeserver...");
|
||||||
print("Checking homeserver...");
|
await client.checkHomeserver(Uri.parse(homeserver));
|
||||||
await client.checkHomeserver(Uri.parse(homeserver));
|
print("Logging in...");
|
||||||
print("Logging in...");
|
await client.login(LoginType.mLoginPassword,
|
||||||
await client.login(LoginType.mLoginPassword,
|
identifier: AuthenticationUserIdentifier(user: username),
|
||||||
identifier: AuthenticationUserIdentifier(user: username),
|
password: password);
|
||||||
password: password);
|
|
||||||
await client.roomsLoading;
|
|
||||||
await client.accountDataLoading;
|
|
||||||
} finally {
|
|
||||||
_loading = false;
|
|
||||||
}
|
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user