Skip to content

Commit 0d61908

Browse files
committed
Support multiple topmost records
1 parent 980b792 commit 0d61908

File tree

2 files changed

+132
-10
lines changed

2 files changed

+132
-10
lines changed

Flow.Launcher.Infrastructure/Storage/JsonStorage.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ public JsonStorage(string filePath)
4545
FilesFolders.ValidateDirectory(DirectoryPath);
4646
}
4747

48+
public bool Exists()
49+
{
50+
return File.Exists(FilePath);
51+
}
52+
4853
public async Task<T> LoadAsync()
4954
{
5055
if (Data != null)

Flow.Launcher/Storage/TopMostRecord.cs

Lines changed: 127 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Collections.Concurrent;
22
using System.Collections.Generic;
3+
using System.Linq;
34
using System.Text.Json.Serialization;
45
using Flow.Launcher.Infrastructure.Storage;
56
using Flow.Launcher.Plugin;
@@ -8,14 +9,29 @@ namespace Flow.Launcher.Storage
89
{
910
public class FlowLauncherJsonStorageTopMostRecord : ISavable
1011
{
11-
private readonly FlowLauncherJsonStorage<TopMostRecord> _topMostRecordStorage;
12-
13-
private readonly TopMostRecord _topMostRecord;
12+
private readonly FlowLauncherJsonStorage<MultipleTopMostRecord> _topMostRecordStorage;
13+
private readonly MultipleTopMostRecord _topMostRecord;
1414

1515
public FlowLauncherJsonStorageTopMostRecord()
1616
{
17-
_topMostRecordStorage = new FlowLauncherJsonStorage<TopMostRecord>();
18-
_topMostRecord = _topMostRecordStorage.Load();
17+
var topMostRecordStorage = new FlowLauncherJsonStorage<TopMostRecord>();
18+
var exist = topMostRecordStorage.Exists();
19+
if (exist)
20+
{
21+
// Get old data
22+
var topMostRecord = topMostRecordStorage.Load();
23+
24+
// Convert to new data
25+
_topMostRecordStorage = new FlowLauncherJsonStorage<MultipleTopMostRecord>();
26+
_topMostRecord = _topMostRecordStorage.Load();
27+
_topMostRecord.Add(topMostRecord);
28+
}
29+
else
30+
{
31+
// Get new data
32+
_topMostRecordStorage = new FlowLauncherJsonStorage<MultipleTopMostRecord>();
33+
_topMostRecord = _topMostRecordStorage.Load();
34+
}
1935
}
2036

2137
public void Save()
@@ -42,7 +58,7 @@ public void AddOrUpdate(Result result)
4258
public class TopMostRecord
4359
{
4460
[JsonInclude]
45-
public ConcurrentDictionary<string, Record> records { get; private set; } = new ConcurrentDictionary<string, Record>();
61+
public ConcurrentDictionary<string, Record> records { get; private set; } = new();
4662

4763
internal bool IsTopMost(Result result)
4864
{
@@ -90,12 +106,113 @@ internal void AddOrUpdate(Result result)
90106
}
91107
}
92108

109+
public class MultipleTopMostRecord
110+
{
111+
[JsonInclude]
112+
public ConcurrentDictionary<string, ConcurrentBag<Record>> records { get; private set; } = new();
113+
114+
internal void Add(TopMostRecord topMostRecord)
115+
{
116+
if (topMostRecord == null || topMostRecord.records.IsEmpty)
117+
{
118+
return;
119+
}
120+
121+
foreach (var record in topMostRecord.records)
122+
{
123+
records.AddOrUpdate(record.Key, new ConcurrentBag<Record> { record.Value }, (key, oldValue) =>
124+
{
125+
oldValue.Add(record.Value);
126+
return oldValue;
127+
});
128+
}
129+
}
130+
131+
internal bool IsTopMost(Result result)
132+
{
133+
// origin query is null when user select the context menu item directly of one item from query list
134+
// in this case, we do not need to check if the result is top most
135+
if (records.IsEmpty || result.OriginQuery == null ||
136+
!records.TryGetValue(result.OriginQuery.RawQuery, out var value))
137+
{
138+
return false;
139+
}
140+
141+
// since this dictionary should be very small (or empty) going over it should be pretty fast.
142+
return value.Any(record => record.Equals(result));
143+
}
144+
145+
internal void Remove(Result result)
146+
{
147+
// origin query is null when user select the context menu item directly of one item from query list
148+
// in this case, we do not need to remove the record
149+
if (result.OriginQuery == null ||
150+
!records.TryGetValue(result.OriginQuery.RawQuery, out var value))
151+
{
152+
return;
153+
}
154+
155+
// remove the record from the bag
156+
var recordToRemove = value.FirstOrDefault(r => r.Equals(result));
157+
if (recordToRemove != null)
158+
{
159+
value.TryTake(out recordToRemove);
160+
}
161+
}
162+
163+
internal void AddOrUpdate(Result result)
164+
{
165+
// origin query is null when user select the context menu item directly of one item from query list
166+
// in this case, we do not need to add or update the record
167+
if (result.OriginQuery == null)
168+
{
169+
return;
170+
}
171+
172+
var record = new Record
173+
{
174+
PluginID = result.PluginID,
175+
Title = result.Title,
176+
SubTitle = result.SubTitle,
177+
RecordKey = result.RecordKey
178+
};
179+
if (!records.TryGetValue(result.OriginQuery.RawQuery, out var value))
180+
{
181+
// create a new bag if it does not exist
182+
value = new ConcurrentBag<Record>()
183+
{
184+
record
185+
};
186+
records.TryAdd(result.OriginQuery.RawQuery, value);
187+
}
188+
else
189+
{
190+
// add or update the record in the bag
191+
if (value.Any(r => r.Equals(result)))
192+
{
193+
// update the record
194+
var recordToUpdate = value.FirstOrDefault(r => r.Equals(result));
195+
if (recordToUpdate != null)
196+
{
197+
value.TryTake(out recordToUpdate);
198+
value.Add(record);
199+
}
200+
}
201+
else
202+
{
203+
// add the record
204+
value.Add(record);
205+
}
206+
}
207+
}
208+
}
209+
93210
public class Record
94211
{
95-
public string Title { get; set; }
96-
public string SubTitle { get; set; }
97-
public string PluginID { get; set; }
98-
public string RecordKey { get; set; }
212+
public string Title { get; init; }
213+
public string SubTitle { get; init; }
214+
public string PluginID { get; init; }
215+
public string RecordKey { get; init; }
99216

100217
public bool Equals(Result r)
101218
{

0 commit comments

Comments
 (0)