Skip to content

Commit a7f92f3

Browse files
committed
Sync recently used reactions list across sessions
Signed-off-by: Michael Telatynski <[email protected]>
1 parent 113a0f1 commit a7f92f3

File tree

4 files changed

+96
-35
lines changed

4 files changed

+96
-35
lines changed

src/emojipicker/recent.js

Lines changed: 0 additions & 35 deletions
This file was deleted.

src/emojipicker/recent.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
Copyright 2019 Tulir Asokan <[email protected]>
3+
Copyright 2020 The Matrix.org Foundation C.I.C.
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
*/
17+
18+
import SettingsStore, {SettingLevel} from "../settings/SettingsStore";
19+
import {sortBy} from "lodash";
20+
21+
interface ILegacyFormat {
22+
[emoji: string]: [number, number]; // [count, date]
23+
}
24+
25+
// New format tries to be more space efficient for synchronization. Ordered by Date descending.
26+
type Format = [string, number][]; // [emoji, count]
27+
28+
const SETTING_NAME = "recent_emoji";
29+
30+
// we store more recents than we typically query but this lets us sort by weighted usage
31+
// even if you haven't used your typically favourite emoji for a little while.
32+
const STORAGE_LIMIT = 100;
33+
34+
// TODO remove this after some time
35+
function migrate() {
36+
const data: ILegacyFormat = JSON.parse(window.localStorage.mx_reaction_count || '{}');
37+
const sorted = Object.entries(data).sort(([, [count1, date1]], [, [count2, date2]]) => date2 - date1);
38+
const newFormat = sorted.map(([emoji, [count, date]]) => [emoji, count]);
39+
SettingsStore.setValue(SETTING_NAME, null, SettingLevel.ACCOUNT, newFormat.slice(0, STORAGE_LIMIT));
40+
}
41+
42+
function getRecentEmoji(): Format {
43+
return SettingsStore.getValue(SETTING_NAME) || [];
44+
}
45+
46+
export function add(emoji: string) {
47+
const recents = getRecentEmoji();
48+
const i = recents.findIndex(([e]) => e === emoji);
49+
50+
let newEntry;
51+
if (i >= 0) {
52+
// first remove the existing tuple so that we can increment it and push it to the front
53+
[newEntry] = recents.splice(i, 1);
54+
newEntry[1]++; // increment the usage count
55+
} else {
56+
newEntry = [emoji, 1];
57+
}
58+
59+
SettingsStore.setValue(SETTING_NAME, null, SettingLevel.ACCOUNT, [newEntry, ...recents].slice(0, STORAGE_LIMIT));
60+
}
61+
62+
export function get(limit = 24) {
63+
let recents = getRecentEmoji();
64+
65+
if (recents.length < 1) {
66+
migrate();
67+
recents = getRecentEmoji();
68+
}
69+
70+
// perform a stable sort on `count` to keep the recent (date) order as a secondary sort factor
71+
const sorted = sortBy(recents, "1");
72+
return sorted.slice(0, limit).map(([emoji]) => emoji);
73+
}

src/settings/Settings.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,12 @@ export const SETTINGS = {
351351
default: "en",
352352
},
353353
"breadcrumb_rooms": {
354+
// not really a setting
355+
supportedLevels: ['account'],
356+
default: [],
357+
},
358+
"recent_emoji": {
359+
// not really a setting
354360
supportedLevels: ['account'],
355361
default: [],
356362
},

src/settings/handlers/AccountSettingsHandler.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {objectClone, objectKeyChanges} from "../../utils/objects";
2323
const BREADCRUMBS_LEGACY_EVENT_TYPE = "im.vector.riot.breadcrumb_rooms";
2424
const BREADCRUMBS_EVENT_TYPE = "im.vector.setting.breadcrumbs";
2525
const BREADCRUMBS_EVENT_TYPES = [BREADCRUMBS_LEGACY_EVENT_TYPE, BREADCRUMBS_EVENT_TYPE];
26+
const RECENT_EMOJI_EVENT_TYPE = "io.element.recent_emoji";
2627

2728
const INTEG_PROVISIONING_EVENT_TYPE = "im.vector.setting.integration_provisioning";
2829

@@ -69,6 +70,9 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa
6970
} else if (event.getType() === INTEG_PROVISIONING_EVENT_TYPE) {
7071
const val = event.getContent()['enabled'];
7172
this._watchers.notifyUpdate("integrationProvisioning", null, SettingLevel.ACCOUNT, val);
73+
} else if (event.getType() === RECENT_EMOJI_EVENT_TYPE) {
74+
const val = event.getContent()['enabled'];
75+
this._watchers.notifyUpdate("recent_emoji", null, SettingLevel.ACCOUNT, val);
7276
}
7377
}
7478

@@ -95,6 +99,12 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa
9599
return content && content['recent_rooms'] ? content['recent_rooms'] : [];
96100
}
97101

102+
// Special case recent emoji
103+
if (settingName === "recent_emoji") {
104+
const content = this._getSettings(RECENT_EMOJI_EVENT_TYPE);
105+
return content ? content["recent_emoji"] : null;
106+
}
107+
98108
// Special case integration manager provisioning
99109
if (settingName === "integrationProvisioning") {
100110
const content = this._getSettings(INTEG_PROVISIONING_EVENT_TYPE);
@@ -135,6 +145,13 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa
135145
return MatrixClientPeg.get().setAccountData(BREADCRUMBS_EVENT_TYPE, content);
136146
}
137147

148+
// Special case recent emoji
149+
if (settingName === "recent_emoji") {
150+
const content = this._getSettings(RECENT_EMOJI_EVENT_TYPE) || {};
151+
content["recent_emoji"] = newValue;
152+
return MatrixClientPeg.get().setAccountData(RECENT_EMOJI_EVENT_TYPE, content);
153+
}
154+
138155
// Special case integration manager provisioning
139156
if (settingName === "integrationProvisioning") {
140157
const content = this._getSettings(INTEG_PROVISIONING_EVENT_TYPE) || {};

0 commit comments

Comments
 (0)