mirror of
https://github.com/element-hq/element-web
synced 2024-11-27 11:47:23 +03:00
Merge pull request #4993 from matrix-org/t3chguy/fix/14476
Sync recently used reactions list across sessions
This commit is contained in:
commit
1dac3840fd
4 changed files with 96 additions and 35 deletions
|
@ -1,35 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2019 Tulir Asokan <tulir@maunium.net>
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const REACTION_COUNT = JSON.parse(window.localStorage.mx_reaction_count || '{}');
|
|
||||||
let sorted = null;
|
|
||||||
|
|
||||||
export function add(emoji) {
|
|
||||||
const [count] = REACTION_COUNT[emoji] || [0];
|
|
||||||
REACTION_COUNT[emoji] = [count + 1, Date.now()];
|
|
||||||
window.localStorage.mx_reaction_count = JSON.stringify(REACTION_COUNT);
|
|
||||||
sorted = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function get(limit = 24) {
|
|
||||||
if (sorted === null) {
|
|
||||||
sorted = Object.entries(REACTION_COUNT)
|
|
||||||
.sort(([, [count1, date1]], [, [count2, date2]]) =>
|
|
||||||
count2 === count1 ? date2 - date1 : count2 - count1)
|
|
||||||
.map(([emoji, count]) => emoji);
|
|
||||||
}
|
|
||||||
return sorted.slice(0, limit);
|
|
||||||
}
|
|
73
src/emojipicker/recent.ts
Normal file
73
src/emojipicker/recent.ts
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
Copyright 2019 Tulir Asokan <tulir@maunium.net>
|
||||||
|
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import SettingsStore, {SettingLevel} from "../settings/SettingsStore";
|
||||||
|
import {sortBy} from "lodash";
|
||||||
|
|
||||||
|
interface ILegacyFormat {
|
||||||
|
[emoji: string]: [number, number]; // [count, date]
|
||||||
|
}
|
||||||
|
|
||||||
|
// New format tries to be more space efficient for synchronization. Ordered by Date descending.
|
||||||
|
type Format = [string, number][]; // [emoji, count]
|
||||||
|
|
||||||
|
const SETTING_NAME = "recent_emoji";
|
||||||
|
|
||||||
|
// we store more recents than we typically query but this lets us sort by weighted usage
|
||||||
|
// even if you haven't used your typically favourite emoji for a little while.
|
||||||
|
const STORAGE_LIMIT = 100;
|
||||||
|
|
||||||
|
// TODO remove this after some time
|
||||||
|
function migrate() {
|
||||||
|
const data: ILegacyFormat = JSON.parse(window.localStorage.mx_reaction_count || '{}');
|
||||||
|
const sorted = Object.entries(data).sort(([, [count1, date1]], [, [count2, date2]]) => date2 - date1);
|
||||||
|
const newFormat = sorted.map(([emoji, [count, date]]) => [emoji, count]);
|
||||||
|
SettingsStore.setValue(SETTING_NAME, null, SettingLevel.ACCOUNT, newFormat.slice(0, STORAGE_LIMIT));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRecentEmoji(): Format {
|
||||||
|
return SettingsStore.getValue(SETTING_NAME) || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function add(emoji: string) {
|
||||||
|
const recents = getRecentEmoji();
|
||||||
|
const i = recents.findIndex(([e]) => e === emoji);
|
||||||
|
|
||||||
|
let newEntry;
|
||||||
|
if (i >= 0) {
|
||||||
|
// first remove the existing tuple so that we can increment it and push it to the front
|
||||||
|
[newEntry] = recents.splice(i, 1);
|
||||||
|
newEntry[1]++; // increment the usage count
|
||||||
|
} else {
|
||||||
|
newEntry = [emoji, 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsStore.setValue(SETTING_NAME, null, SettingLevel.ACCOUNT, [newEntry, ...recents].slice(0, STORAGE_LIMIT));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function get(limit = 24) {
|
||||||
|
let recents = getRecentEmoji();
|
||||||
|
|
||||||
|
if (recents.length < 1) {
|
||||||
|
migrate();
|
||||||
|
recents = getRecentEmoji();
|
||||||
|
}
|
||||||
|
|
||||||
|
// perform a stable sort on `count` to keep the recent (date) order as a secondary sort factor
|
||||||
|
const sorted = sortBy(recents, "1");
|
||||||
|
return sorted.slice(0, limit).map(([emoji]) => emoji);
|
||||||
|
}
|
|
@ -357,6 +357,12 @@ export const SETTINGS = {
|
||||||
default: "en",
|
default: "en",
|
||||||
},
|
},
|
||||||
"breadcrumb_rooms": {
|
"breadcrumb_rooms": {
|
||||||
|
// not really a setting
|
||||||
|
supportedLevels: ['account'],
|
||||||
|
default: [],
|
||||||
|
},
|
||||||
|
"recent_emoji": {
|
||||||
|
// not really a setting
|
||||||
supportedLevels: ['account'],
|
supportedLevels: ['account'],
|
||||||
default: [],
|
default: [],
|
||||||
},
|
},
|
||||||
|
|
|
@ -23,6 +23,7 @@ import {objectClone, objectKeyChanges} from "../../utils/objects";
|
||||||
const BREADCRUMBS_LEGACY_EVENT_TYPE = "im.vector.riot.breadcrumb_rooms";
|
const BREADCRUMBS_LEGACY_EVENT_TYPE = "im.vector.riot.breadcrumb_rooms";
|
||||||
const BREADCRUMBS_EVENT_TYPE = "im.vector.setting.breadcrumbs";
|
const BREADCRUMBS_EVENT_TYPE = "im.vector.setting.breadcrumbs";
|
||||||
const BREADCRUMBS_EVENT_TYPES = [BREADCRUMBS_LEGACY_EVENT_TYPE, BREADCRUMBS_EVENT_TYPE];
|
const BREADCRUMBS_EVENT_TYPES = [BREADCRUMBS_LEGACY_EVENT_TYPE, BREADCRUMBS_EVENT_TYPE];
|
||||||
|
const RECENT_EMOJI_EVENT_TYPE = "io.element.recent_emoji";
|
||||||
|
|
||||||
const INTEG_PROVISIONING_EVENT_TYPE = "im.vector.setting.integration_provisioning";
|
const INTEG_PROVISIONING_EVENT_TYPE = "im.vector.setting.integration_provisioning";
|
||||||
|
|
||||||
|
@ -69,6 +70,9 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa
|
||||||
} else if (event.getType() === INTEG_PROVISIONING_EVENT_TYPE) {
|
} else if (event.getType() === INTEG_PROVISIONING_EVENT_TYPE) {
|
||||||
const val = event.getContent()['enabled'];
|
const val = event.getContent()['enabled'];
|
||||||
this._watchers.notifyUpdate("integrationProvisioning", null, SettingLevel.ACCOUNT, val);
|
this._watchers.notifyUpdate("integrationProvisioning", null, SettingLevel.ACCOUNT, val);
|
||||||
|
} else if (event.getType() === RECENT_EMOJI_EVENT_TYPE) {
|
||||||
|
const val = event.getContent()['enabled'];
|
||||||
|
this._watchers.notifyUpdate("recent_emoji", null, SettingLevel.ACCOUNT, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,6 +99,12 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa
|
||||||
return content && content['recent_rooms'] ? content['recent_rooms'] : [];
|
return content && content['recent_rooms'] ? content['recent_rooms'] : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Special case recent emoji
|
||||||
|
if (settingName === "recent_emoji") {
|
||||||
|
const content = this._getSettings(RECENT_EMOJI_EVENT_TYPE);
|
||||||
|
return content ? content["recent_emoji"] : null;
|
||||||
|
}
|
||||||
|
|
||||||
// Special case integration manager provisioning
|
// Special case integration manager provisioning
|
||||||
if (settingName === "integrationProvisioning") {
|
if (settingName === "integrationProvisioning") {
|
||||||
const content = this._getSettings(INTEG_PROVISIONING_EVENT_TYPE);
|
const content = this._getSettings(INTEG_PROVISIONING_EVENT_TYPE);
|
||||||
|
@ -135,6 +145,13 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa
|
||||||
return MatrixClientPeg.get().setAccountData(BREADCRUMBS_EVENT_TYPE, content);
|
return MatrixClientPeg.get().setAccountData(BREADCRUMBS_EVENT_TYPE, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Special case recent emoji
|
||||||
|
if (settingName === "recent_emoji") {
|
||||||
|
const content = this._getSettings(RECENT_EMOJI_EVENT_TYPE) || {};
|
||||||
|
content["recent_emoji"] = newValue;
|
||||||
|
return MatrixClientPeg.get().setAccountData(RECENT_EMOJI_EVENT_TYPE, content);
|
||||||
|
}
|
||||||
|
|
||||||
// Special case integration manager provisioning
|
// Special case integration manager provisioning
|
||||||
if (settingName === "integrationProvisioning") {
|
if (settingName === "integrationProvisioning") {
|
||||||
const content = this._getSettings(INTEG_PROVISIONING_EVENT_TYPE) || {};
|
const content = this._getSettings(INTEG_PROVISIONING_EVENT_TYPE) || {};
|
||||||
|
|
Loading…
Reference in a new issue