Greatly imporve initial loading performance
This commit is contained in:
parent
00b844c118
commit
a1f8120c59
|
@ -533,6 +533,10 @@ class Client {
|
||||||
final StreamController<KeyVerification> onKeyVerificationRequest =
|
final StreamController<KeyVerification> onKeyVerificationRequest =
|
||||||
StreamController.broadcast();
|
StreamController.broadcast();
|
||||||
|
|
||||||
|
/// When a new update entered, be it a sync or an avatar post-loaded
|
||||||
|
/// payload will always be true
|
||||||
|
final StreamController<bool> onUpdate = StreamController.broadcast();
|
||||||
|
|
||||||
/// Matrix synchronisation is done with https long polling. This needs a
|
/// Matrix synchronisation is done with https long polling. This needs a
|
||||||
/// timeout which is usually 30 seconds.
|
/// timeout which is usually 30 seconds.
|
||||||
int syncTimeoutSec = 30;
|
int syncTimeoutSec = 30;
|
||||||
|
@ -642,6 +646,9 @@ class Client {
|
||||||
}
|
}
|
||||||
_userDeviceKeys = await database.getUserDeviceKeys(this);
|
_userDeviceKeys = await database.getUserDeviceKeys(this);
|
||||||
_rooms = await database.getRoomList(this, onlyLeft: false);
|
_rooms = await database.getRoomList(this, onlyLeft: false);
|
||||||
|
for (final r in rooms) {
|
||||||
|
r.onUpdate.stream.listen((v) => _addUpdate());
|
||||||
|
}
|
||||||
_sortRooms();
|
_sortRooms();
|
||||||
accountData = await database.getAccountData(id);
|
accountData = await database.getAccountData(id);
|
||||||
presences = await database.getPresences(id);
|
presences = await database.getPresences(id);
|
||||||
|
@ -769,6 +776,7 @@ class Client {
|
||||||
encryption.handleDeviceOneTimeKeysCount(sync.deviceOneTimeKeysCount);
|
encryption.handleDeviceOneTimeKeysCount(sync.deviceOneTimeKeysCount);
|
||||||
}
|
}
|
||||||
onSync.add(sync);
|
onSync.add(sync);
|
||||||
|
_addUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _handleDeviceListsEvents(DeviceListsUpdate deviceLists) async {
|
Future<void> _handleDeviceListsEvents(DeviceListsUpdate deviceLists) async {
|
||||||
|
@ -1009,6 +1017,7 @@ class Client {
|
||||||
roomAccountData: {},
|
roomAccountData: {},
|
||||||
client: this,
|
client: this,
|
||||||
);
|
);
|
||||||
|
newRoom.onUpdate.stream.listen((v) => _addUpdate());
|
||||||
rooms.insert(position, newRoom);
|
rooms.insert(position, newRoom);
|
||||||
}
|
}
|
||||||
// If the membership is "leave" then remove the item and stop here
|
// If the membership is "leave" then remove the item and stop here
|
||||||
|
@ -1419,6 +1428,18 @@ class Client {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Timer _updateTimer;
|
||||||
|
|
||||||
|
void _addUpdate() {
|
||||||
|
// we only want max. one update per 50ms
|
||||||
|
if (_updateTimer == null) {
|
||||||
|
_updateTimer = Timer(Duration(milliseconds: 50), () {
|
||||||
|
onUpdate.add(true);
|
||||||
|
_updateTimer = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool _disposed = false;
|
bool _disposed = false;
|
||||||
|
|
||||||
/// Stops the synchronization and closes the database. After this
|
/// Stops the synchronization and closes the database. After this
|
||||||
|
|
|
@ -157,7 +157,7 @@ class Database extends _$Database {
|
||||||
? t.membership.equals('leave')
|
? t.membership.equals('leave')
|
||||||
: t.membership.equals('leave').not()))
|
: t.membership.equals('leave').not()))
|
||||||
.get();
|
.get();
|
||||||
final resStates = await getAllRoomStates(client.id).get();
|
final resStates = await getImportantRoomStates(client.id).get();
|
||||||
final resAccountData = await getAllRoomAccountData(client.id).get();
|
final resAccountData = await getAllRoomAccountData(client.id).get();
|
||||||
final roomList = <sdk.Room>[];
|
final roomList = <sdk.Room>[];
|
||||||
for (final r in res) {
|
for (final r in res) {
|
||||||
|
|
|
@ -6077,6 +6077,13 @@ abstract class _$Database extends GeneratedDatabase {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Selectable<DbRoomState> getImportantRoomStates(int client_id) {
|
||||||
|
return customSelect(
|
||||||
|
'SELECT * FROM room_states WHERE client_id = :client_id AND type IN (\'m.room.name\', \'m.room.avatar\', \'m.room.message\', \'m.room.encrypted\', \'m.room.encryption\')',
|
||||||
|
variables: [Variable.withInt(client_id)],
|
||||||
|
readsFrom: {roomStates}).map(_rowToDbRoomState);
|
||||||
|
}
|
||||||
|
|
||||||
Selectable<DbRoomState> getAllRoomStates(int client_id) {
|
Selectable<DbRoomState> getAllRoomStates(int client_id) {
|
||||||
return customSelect(
|
return customSelect(
|
||||||
'SELECT * FROM room_states WHERE client_id = :client_id',
|
'SELECT * FROM room_states WHERE client_id = :client_id',
|
||||||
|
@ -6084,6 +6091,14 @@ abstract class _$Database extends GeneratedDatabase {
|
||||||
readsFrom: {roomStates}).map(_rowToDbRoomState);
|
readsFrom: {roomStates}).map(_rowToDbRoomState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Selectable<DbRoomState> getAllRoomStatesForRoom(
|
||||||
|
int client_id, String room_id) {
|
||||||
|
return customSelect(
|
||||||
|
'SELECT * FROM room_states WHERE client_id = :client_id AND room_id = :room_id',
|
||||||
|
variables: [Variable.withInt(client_id), Variable.withString(room_id)],
|
||||||
|
readsFrom: {roomStates}).map(_rowToDbRoomState);
|
||||||
|
}
|
||||||
|
|
||||||
Future<int> storeEvent(
|
Future<int> storeEvent(
|
||||||
int client_id,
|
int client_id,
|
||||||
String event_id,
|
String event_id,
|
||||||
|
|
|
@ -210,7 +210,9 @@ getAllPresences: SELECT * FROM presences WHERE client_id = :client_id;
|
||||||
storePresence: INSERT OR REPLACE INTO presences (client_id, type, sender, content) VALUES (:client_id, :type, :sender, :content);
|
storePresence: INSERT OR REPLACE INTO presences (client_id, type, sender, content) VALUES (:client_id, :type, :sender, :content);
|
||||||
updateEvent: UPDATE events SET unsigned = :unsigned, content = :content, prev_content = :prev_content WHERE client_id = :client_id AND event_id = :event_id AND room_id = :room_id;
|
updateEvent: UPDATE events SET unsigned = :unsigned, content = :content, prev_content = :prev_content WHERE client_id = :client_id AND event_id = :event_id AND room_id = :room_id;
|
||||||
updateEventStatus: UPDATE events SET status = :status, event_id = :new_event_id WHERE client_id = :client_id AND event_id = :old_event_id AND room_id = :room_id;
|
updateEventStatus: UPDATE events SET status = :status, event_id = :new_event_id WHERE client_id = :client_id AND event_id = :old_event_id AND room_id = :room_id;
|
||||||
|
getImportantRoomStates: SELECT * FROM room_states WHERE client_id = :client_id AND type IN ('m.room.name', 'm.room.avatar', 'm.room.message', 'm.room.encrypted', 'm.room.encryption');
|
||||||
getAllRoomStates: SELECT * FROM room_states WHERE client_id = :client_id;
|
getAllRoomStates: SELECT * FROM room_states WHERE client_id = :client_id;
|
||||||
|
getAllRoomStatesForRoom: SELECT * FROM room_states WHERE client_id = :client_id AND room_id = :room_id;
|
||||||
storeEvent: INSERT OR REPLACE INTO events (client_id, event_id, room_id, sort_order, origin_server_ts, sender, type, unsigned, content, prev_content, state_key, status) VALUES (:client_id, :event_id, :room_id, :sort_order, :origin_server_ts, :sender, :type, :unsigned, :content, :prev_content, :state_key, :status);
|
storeEvent: INSERT OR REPLACE INTO events (client_id, event_id, room_id, sort_order, origin_server_ts, sender, type, unsigned, content, prev_content, state_key, status) VALUES (:client_id, :event_id, :room_id, :sort_order, :origin_server_ts, :sender, :type, :unsigned, :content, :prev_content, :state_key, :status);
|
||||||
storeRoomState: INSERT OR REPLACE INTO room_states (client_id, event_id, room_id, sort_order, origin_server_ts, sender, type, unsigned, content, prev_content, state_key) VALUES (:client_id, :event_id, :room_id, :sort_order, :origin_server_ts, :sender, :type, :unsigned, :content, :prev_content, :state_key);
|
storeRoomState: INSERT OR REPLACE INTO room_states (client_id, event_id, room_id, sort_order, origin_server_ts, sender, type, unsigned, content, prev_content, state_key) VALUES (:client_id, :event_id, :room_id, :sort_order, :origin_server_ts, :sender, :type, :unsigned, :content, :prev_content, :state_key);
|
||||||
getAllRoomAccountData: SELECT * FROM room_account_data WHERE client_id = :client_id;
|
getAllRoomAccountData: SELECT * FROM room_account_data WHERE client_id = :client_id;
|
||||||
|
|
|
@ -101,6 +101,19 @@ class Room {
|
||||||
_oldestSortOrder, _newestSortOrder, client.id, id);
|
_oldestSortOrder, _newestSortOrder, client.id, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool partial = true;
|
||||||
|
Future<void> postLoad() async {
|
||||||
|
if (!partial || client.database == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final allStates = await client.database.getAllRoomStatesForRoom(client.id, id).get();
|
||||||
|
for (final state in allStates) {
|
||||||
|
final newState = Event.fromDb(state, this);
|
||||||
|
setState(newState);
|
||||||
|
}
|
||||||
|
partial = false;
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the [Event] for the given [typeKey] and optional [stateKey].
|
/// Returns the [Event] for the given [typeKey] and optional [stateKey].
|
||||||
/// If no [stateKey] is provided, it defaults to an empty string.
|
/// If no [stateKey] is provided, it defaults to an empty string.
|
||||||
Event getState(String typeKey, [String stateKey = '']) =>
|
Event getState(String typeKey, [String stateKey = '']) =>
|
||||||
|
@ -934,6 +947,7 @@ class Room {
|
||||||
Future<Timeline> getTimeline(
|
Future<Timeline> getTimeline(
|
||||||
{onTimelineUpdateCallback onUpdate,
|
{onTimelineUpdateCallback onUpdate,
|
||||||
onTimelineInsertCallback onInsert}) async {
|
onTimelineInsertCallback onInsert}) async {
|
||||||
|
await postLoad();
|
||||||
var events;
|
var events;
|
||||||
if (client.database != null) {
|
if (client.database != null) {
|
||||||
events = await client.database.getEventList(client.id, this);
|
events = await client.database.getEventList(client.id, this);
|
||||||
|
@ -1033,6 +1047,15 @@ class Room {
|
||||||
if (getState(EventTypes.RoomMember, mxID) != null) {
|
if (getState(EventTypes.RoomMember, mxID) != null) {
|
||||||
return getState(EventTypes.RoomMember, mxID).asUser;
|
return getState(EventTypes.RoomMember, mxID).asUser;
|
||||||
}
|
}
|
||||||
|
if (client.database != null) {
|
||||||
|
// it may be in the database
|
||||||
|
final user = await client.database.getUser(client.id, mxID, this);
|
||||||
|
if (user != null) {
|
||||||
|
setState(user);
|
||||||
|
if (onUpdate != null) onUpdate.add(id);
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (mxID == null || !_requestingMatrixIds.add(mxID)) return null;
|
if (mxID == null || !_requestingMatrixIds.add(mxID)) return null;
|
||||||
Map<String, dynamic> resp;
|
Map<String, dynamic> resp;
|
||||||
try {
|
try {
|
||||||
|
|
Loading…
Reference in a new issue