Skip to content

Commit 2ec3831

Browse files
committed
wire basic query into apps
1 parent 393755b commit 2ec3831

File tree

13 files changed

+673
-134
lines changed

13 files changed

+673
-134
lines changed

ClinicalTrials.Apps/AppShell.xaml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@
1010
<ShellContent
1111
Title="Queries"
1212
ContentTemplate="{DataTemplate local:Queries}"
13-
Route="queries">
14-
<ShellContent Title="Query" Route="query" ContentTemplate="{DataTemplate local:Query}" />
15-
</ShellContent>
13+
Route="queries"/>
14+
<ShellContent
15+
Title="Query"
16+
Route="query"
17+
ContentTemplate="{DataTemplate local:Query}" />
1618

1719
</Shell>
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
using System.Text.Json;
2+
using System.Text.Json.Serialization;
3+
using ClinicalTrials.Core;
4+
5+
namespace ClinicalTrials.Apps
6+
{
7+
public class DeviceProfileUtility : IDataUtility<QueryInfo>
8+
{
9+
private const string extension = ".userdata.json";
10+
11+
public Task<string> GetData(string key)
12+
{
13+
throw new NotImplementedException();
14+
}
15+
16+
public async Task<List<QueryInfo>> GetAllItems()
17+
{
18+
var queryInfos = new List<QueryInfo>();
19+
20+
var keys = await GetAllKeys();
21+
foreach (var key in keys)
22+
{
23+
var queryInfo = await Load(key);
24+
queryInfos.Add(queryInfo);
25+
}
26+
27+
return queryInfos;
28+
}
29+
30+
public async Task<List<string>> GetAllKeys()
31+
{
32+
DirectoryInfo directoryInfo = new DirectoryInfo(FileSystem.Current.AppDataDirectory);
33+
var profileNames = new List<string>();
34+
await Task.Run(() =>
35+
{
36+
var files = directoryInfo.GetFiles("*" + extension);
37+
foreach (var file in files)
38+
{
39+
var keyNameEnd = file.Name.IndexOf(extension);
40+
if (keyNameEnd != -1)
41+
{
42+
var key = file.Name.Substring(0, keyNameEnd);
43+
profileNames.Add(key);
44+
}
45+
}
46+
});
47+
48+
return profileNames.OrderBy(p => p).ToList();
49+
}
50+
51+
public void DeleteItem(string key)
52+
{
53+
var profileFile = GetFilename(key);
54+
File.Delete(profileFile);
55+
}
56+
57+
public void RenameItem(string oldName, string newName)
58+
{
59+
var oldFile = GetFilename(oldName);
60+
var newFile = GetFilename(newName);
61+
if (!File.Exists(newName))
62+
{
63+
if (File.Exists(oldFile))
64+
{
65+
File.Move(oldFile, newFile);
66+
}
67+
else
68+
{
69+
throw new InvalidDataException($"old file '{oldFile}' is missing.");
70+
}
71+
}
72+
73+
throw new InvalidOperationException($"new file '{newFile}' already exists.");
74+
}
75+
76+
public async Task<string> FindProfileName(string baseName)
77+
{
78+
var keys = await GetAllKeys();
79+
int i = 1;
80+
string newKeyName = baseName + i.ToString();
81+
82+
while (i < 10000)
83+
{
84+
if (!keys.Contains(newKeyName))
85+
{
86+
return newKeyName;
87+
}
88+
else
89+
{
90+
newKeyName = baseName + i.ToString();
91+
}
92+
93+
i++;
94+
}
95+
96+
throw new InvalidOperationException("cannot have more than 10,000 names starting with " + baseName);
97+
}
98+
99+
public async Task<QueryInfo> Load(string key)
100+
{
101+
ArgumentNullException.ThrowIfNull(key);
102+
103+
string targetFile = GetFilename(key);
104+
var json = await File.ReadAllTextAsync(targetFile);
105+
106+
if (json != null)
107+
{
108+
var options = new JsonSerializerOptions()
109+
{
110+
Converters =
111+
{
112+
new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)
113+
}
114+
};
115+
116+
var loadedData = QueryInfo.LoadFromJson(json, options);
117+
return loadedData;
118+
}
119+
120+
throw new InvalidDataException($"key '{key}' has invalid data or is missing.");
121+
}
122+
123+
public async Task Save(string? key, QueryInfo? data)
124+
{
125+
var options = new JsonSerializerOptions()
126+
{
127+
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault,
128+
IgnoreReadOnlyProperties = true,
129+
WriteIndented = true,
130+
Converters =
131+
{
132+
new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)
133+
}
134+
};
135+
136+
if (data is not null)
137+
{
138+
var familyDataJson = JsonSerializer.Serialize(data, options);
139+
140+
await Save(key, familyDataJson);
141+
}
142+
}
143+
144+
public async Task Save(string? key, string json)
145+
{
146+
if (key is not null)
147+
{
148+
string targetFile = GetFilename(key);
149+
await File.WriteAllTextAsync(targetFile, json);
150+
}
151+
}
152+
153+
public string GetFilename(string key)
154+
{
155+
return Path.Combine(FileSystem.Current.AppDataDirectory, key + extension);
156+
}
157+
158+
159+
public Task ClearAll()
160+
{
161+
throw new NotImplementedException();
162+
}
163+
}
164+
}

ClinicalTrials.Apps/Queries.xaml.cs

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,56 @@
1-
namespace ClinicalTrials.Apps
1+
using ClinicalTrials.Core;
2+
using System.Collections.ObjectModel;
3+
using static System.Runtime.InteropServices.JavaScript.JSType;
4+
5+
namespace ClinicalTrials.Apps
26
{
37
public partial class Queries : ContentPage
48
{
9+
510
public Queries()
611
{
712
InitializeComponent();
13+
this.Loaded += Queries_Loaded;
814
}
915

10-
private void NewQuery_Clicked(object sender, EventArgs e)
16+
private async void Queries_Loaded(object? sender, EventArgs e)
1117
{
18+
queryFiles.Clear();
19+
20+
var keys = await DeviceProfileUtility.GetAllKeys();
21+
foreach (var key in keys)
22+
{
23+
var queryFile = new QueryFile(key, DeviceProfileUtility.GetFilename(key));
24+
queryFiles.Add(queryFile);
25+
}
1226

27+
queryView.ItemsSource = queryFiles;
1328
}
1429

15-
private void queryView_SelectionChanged(object sender, SelectionChangedEventArgs e)
30+
private async void NewQuery_Clicked(object sender, EventArgs e)
1631
{
32+
var key = await DeviceProfileUtility.FindProfileName("untitled");
33+
var queryInfo = new QueryInfo(key);
34+
await DeviceProfileUtility.Save(key, queryInfo);
35+
var queryFile = new QueryFile(key, DeviceProfileUtility.GetFilename(key));
36+
queryFiles.Insert(0, queryFile);
37+
}
1738

39+
private async void queryView_SelectionChanged(object sender, SelectionChangedEventArgs e)
40+
{
41+
var selectedQuery = queryView.SelectedItem as QueryFile;
42+
if (selectedQuery != null)
43+
{
44+
await NavigateToProfile(selectedQuery.Name);
45+
}
1846
}
47+
48+
private async Task NavigateToProfile(string key)
49+
{
50+
await Shell.Current.GoToAsync(state: "///query?name=" + key);
51+
}
52+
53+
private ObservableCollection<QueryFile> queryFiles = [];
54+
private static DeviceProfileUtility DeviceProfileUtility { get; set; } = new DeviceProfileUtility();
1955
}
2056
}

ClinicalTrials.Apps/Query.xaml

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,33 @@
11
<?xml version="1.0" encoding="utf-8" ?>
22
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
33
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
4+
xmlns:m="clr-namespace:ClinicalTrials.Core;assembly=ClinicalTrials.Core"
5+
xmlns:a="clr-namespace:ClinicalTrials.Apps"
46
x:Class="ClinicalTrials.Apps.Query"
5-
Title="Query">
6-
<VerticalStackLayout>
7-
8-
</VerticalStackLayout>
7+
x:DataType="m:QueryInfo"
8+
>
9+
<Shell.TitleView>
10+
<Grid ColumnDefinitions="*,*,*" x:Name="titleView">
11+
<Button Text="&lt;" Clicked="Back_Clicked" Background="Transparent" />
12+
<Label Text="{Binding Name}" TextColor="{AppThemeBinding Dark=White, Light=Black}" FontAttributes="Bold" FontSize="Medium" HorizontalOptions="Center" VerticalOptions="Center" Grid.Column="1" x:Name="profileLabel"/>
13+
<HorizontalStackLayout Grid.Column="2" HorizontalOptions="End">
14+
<Button Text="Save" Clicked="Save_Clicked" />
15+
</HorizontalStackLayout>
16+
</Grid>
17+
</Shell.TitleView>
18+
<Grid ColumnDefinitions="Auto,*,Auto" RowDefinitions="Auto,*">
19+
<Label Text="ClinicalTrials.gov search:" Grid.Column="0"/>
20+
<Entry Text="{Binding Terms}" Grid.Column="1" x:Name="terms" />
21+
<Button Text="Go" Clicked="Go_Clicked" Grid.Column="2"/>
22+
<CollectionView x:Name="trialsView" ItemsSource="{Binding Trials}" Grid.Row="1" Grid.ColumnSpan="3">
23+
<CollectionView.ItemTemplate>
24+
<DataTemplate x:DataType="m:Trial">
25+
<Grid RowDefinitions="Auto,Auto,10">
26+
<Label Text="{Binding NCTIdValue}" />
27+
<Label Text="{Binding PhaseInfo.Name}" Grid.Row="1" />
28+
</Grid>
29+
</DataTemplate>
30+
</CollectionView.ItemTemplate>
31+
</CollectionView>
32+
</Grid>
933
</ContentPage>

0 commit comments

Comments
 (0)