1 #include "SearchController.h"
2 
3 #include "SearchModel.h"
4 #include "SearchView.h"
5 
6 #include "gui/dialogues/ConfirmPrompt.h"
7 #include "gui/preview/PreviewController.h"
8 #include "gui/preview/PreviewView.h"
9 
10 #include "tasks/Task.h"
11 #include "tasks/TaskWindow.h"
12 
13 #include "Platform.h"
14 #include "Controller.h"
15 
16 #include "graphics/Graphics.h"
17 
18 #include "client/Client.h"
19 
20 #include "common/tpt-minmax.h"
21 
SearchController(std::function<void ()> onDone_)22 SearchController::SearchController(std::function<void ()> onDone_):
23 	activePreview(NULL),
24 	nextQueryTime(0.0f),
25 	nextQueryDone(true),
26 	instantOpen(false),
27 	doRefresh(false),
28 	HasExited(false)
29 {
30 	searchModel = new SearchModel();
31 	searchView = new SearchView();
32 	searchModel->AddObserver(searchView);
33 	searchView->AttachController(this);
34 
35 	searchModel->UpdateSaveList(1, "");
36 
37 	onDone = onDone_;
38 }
39 
GetLoadedSave()40 SaveInfo * SearchController::GetLoadedSave()
41 {
42 	return searchModel->GetLoadedSave();
43 }
44 
ReleaseLoadedSave()45 void SearchController::ReleaseLoadedSave()
46 {
47 	searchModel->SetLoadedSave(NULL);
48 }
49 
Update()50 void SearchController::Update()
51 {
52 	if (doRefresh)
53 	{
54 		if (searchModel->UpdateSaveList(searchModel->GetPageNum(), searchModel->GetLastQuery()))
55 		{
56 			nextQueryDone = true;
57 			doRefresh = false;
58 		}
59 	}
60 	else if (!nextQueryDone && nextQueryTime < Platform::GetTime())
61 	{
62 		if (searchModel->UpdateSaveList(1, nextQuery))
63 			nextQueryDone = true;
64 	}
65 	searchModel->Update();
66 	if(activePreview && activePreview->HasExited)
67 	{
68 		delete activePreview;
69 		activePreview = NULL;
70 		if(searchModel->GetLoadedSave())
71 		{
72 			Exit();
73 		}
74 	}
75 }
76 
Exit()77 void SearchController::Exit()
78 {
79 	InstantOpen(false);
80 	searchView->CloseActiveWindow();
81 	if (onDone)
82 		onDone();
83 	//HasExited = true;
84 }
85 
~SearchController()86 SearchController::~SearchController()
87 {
88 	delete activePreview;
89 	searchView->CloseActiveWindow();
90 	delete searchModel;
91 	delete searchView;
92 }
93 
DoSearch(String query,bool now)94 void SearchController::DoSearch(String query, bool now)
95 {
96 	nextQuery = query;
97 	if (!now)
98 	{
99 		nextQueryTime = Platform::GetTime()+600;
100 		nextQueryDone = false;
101 	}
102 	else
103 	{
104 		nextQueryDone = searchModel->UpdateSaveList(1, nextQuery);
105 	}
106 }
107 
DoSearch2(String query)108 void SearchController::DoSearch2(String query)
109 {
110 	// calls SearchView function to set textbox text, then calls DoSearch
111 	searchView->Search(query);
112 }
113 
Refresh()114 void SearchController::Refresh()
115 {
116 	doRefresh = true;
117 }
118 
SetPage(int page)119 void SearchController::SetPage(int page)
120 {
121 	if (page != searchModel->GetPageNum() && page > 0 && page <= searchModel->GetPageCount())
122 		searchModel->UpdateSaveList(page, searchModel->GetLastQuery());
123 }
124 
SetPageRelative(int offset)125 void SearchController::SetPageRelative(int offset)
126 {
127 	int page = std::min(std::max(searchModel->GetPageNum() + offset, 1), searchModel->GetPageCount());
128 	if (page != searchModel->GetPageNum())
129 		searchModel->UpdateSaveList(page, searchModel->GetLastQuery());
130 }
131 
ChangeSort()132 void SearchController::ChangeSort()
133 {
134 	if(searchModel->GetSort() == "new")
135 	{
136 		searchModel->SetSort("best");
137 	}
138 	else
139 	{
140 		searchModel->SetSort("new");
141 	}
142 	searchModel->UpdateSaveList(1, searchModel->GetLastQuery());
143 }
144 
ShowOwn(bool show)145 void SearchController::ShowOwn(bool show)
146 {
147 	if(Client::Ref().GetAuthUser().UserID)
148 	{
149 		searchModel->SetShowFavourite(false);
150 		searchModel->SetShowOwn(show);
151 	}
152 	else
153 		searchModel->SetShowOwn(false);
154 	searchModel->UpdateSaveList(1, searchModel->GetLastQuery());
155 }
156 
ShowFavourite(bool show)157 void SearchController::ShowFavourite(bool show)
158 {
159 	if(Client::Ref().GetAuthUser().UserID)
160 	{
161 		searchModel->SetShowOwn(false);
162 		searchModel->SetShowFavourite(show);
163 	}
164 	else
165 		searchModel->SetShowFavourite(false);
166 	searchModel->UpdateSaveList(1, searchModel->GetLastQuery());
167 }
168 
Selected(int saveID,bool selected)169 void SearchController::Selected(int saveID, bool selected)
170 {
171 	if(!Client::Ref().GetAuthUser().UserID)
172 		return;
173 
174 	if(selected)
175 		searchModel->SelectSave(saveID);
176 	else
177 		searchModel->DeselectSave(saveID);
178 }
179 
InstantOpen(bool instant)180 void SearchController::InstantOpen(bool instant)
181 {
182 	instantOpen = instant;
183 }
184 
OpenSaveDone()185 void SearchController::OpenSaveDone()
186 {
187 	if (activePreview->GetDoOpen() && activePreview->GetSaveInfo())
188 	{
189 		searchModel->SetLoadedSave(activePreview->GetSaveInfo());
190 	}
191 	else
192 	{
193 		searchModel->SetLoadedSave(NULL);
194 	}
195 }
196 
OpenSave(int saveID)197 void SearchController::OpenSave(int saveID)
198 {
199 	delete activePreview;
200 	Graphics * g = searchView->GetGraphics();
201 	g->fillrect(XRES/3, WINDOWH-20, XRES/3, 20, 0, 0, 0, 150); //dim the "Page X of Y" a little to make the CopyTextButton more noticeable
202 	activePreview = new PreviewController(saveID, 0, instantOpen, [this] { OpenSaveDone(); });
203 	activePreview->GetView()->MakeActiveWindow();
204 }
205 
OpenSave(int saveID,int saveDate)206 void SearchController::OpenSave(int saveID, int saveDate)
207 {
208 	delete activePreview;
209 	Graphics * g = searchView->GetGraphics();
210 	g->fillrect(XRES/3, WINDOWH-20, XRES/3, 20, 0, 0, 0, 150); //dim the "Page X of Y" a little to make the CopyTextButton more noticeable
211 	activePreview = new PreviewController(saveID, saveDate, instantOpen, [this] { OpenSaveDone(); });
212 	activePreview->GetView()->MakeActiveWindow();
213 }
214 
ClearSelection()215 void SearchController::ClearSelection()
216 {
217 	searchModel->ClearSelected();
218 }
219 
RemoveSelected()220 void SearchController::RemoveSelected()
221 {
222 	StringBuilder desc;
223 	desc << "Are you sure you want to delete " << searchModel->GetSelected().size() << " save";
224 	if(searchModel->GetSelected().size()>1)
225 		desc << "s";
226 	desc << "?";
227 	new ConfirmPrompt("Delete saves", desc.Build(), { [this] {
228 		removeSelectedC();
229 	} });
230 }
231 
removeSelectedC()232 void SearchController::removeSelectedC()
233 {
234 	class RemoveSavesTask : public Task
235 	{
236 		SearchController *c;
237 		std::vector<int> saves;
238 	public:
239 		RemoveSavesTask(std::vector<int> saves_, SearchController *c_) { saves = saves_; c = c_; }
240 		bool doWork() override
241 		{
242 			for (size_t i = 0; i < saves.size(); i++)
243 			{
244 				notifyStatus(String::Build("Deleting save [", saves[i], "] ..."));
245 				if (Client::Ref().DeleteSave(saves[i])!=RequestOkay)
246 				{
247 					notifyError(String::Build("Failed to delete [", saves[i], "]: ", Client::Ref().GetLastError()));
248 					c->Refresh();
249 					return false;
250 				}
251 				notifyProgress((float(i+1)/float(saves.size())*100));
252 			}
253 			c->Refresh();
254 			return true;
255 		}
256 	};
257 
258 	std::vector<int> selected = searchModel->GetSelected();
259 	new TaskWindow("Removing saves", new RemoveSavesTask(selected, this));
260 	ClearSelection();
261 	searchModel->UpdateSaveList(searchModel->GetPageNum(), searchModel->GetLastQuery());
262 }
263 
UnpublishSelected(bool publish)264 void SearchController::UnpublishSelected(bool publish)
265 {
266 	StringBuilder desc;
267 	desc << "Are you sure you want to " << (publish ? String("publish ") : String("unpublish ")) << searchModel->GetSelected().size() << " save";
268 	if (searchModel->GetSelected().size() > 1)
269 		desc << "s";
270 	desc << "?";
271 	new ConfirmPrompt(publish ? String("Publish Saves") : String("Unpublish Saves"), desc.Build(), { [this, publish] {
272 		unpublishSelectedC(publish);
273 	} });
274 }
275 
unpublishSelectedC(bool publish)276 void SearchController::unpublishSelectedC(bool publish)
277 {
278 	class UnpublishSavesTask : public Task
279 	{
280 		std::vector<int> saves;
281 		SearchController *c;
282 		bool publish;
283 	public:
284 		UnpublishSavesTask(std::vector<int> saves_, SearchController *c_, bool publish_) { saves = saves_; c = c_; publish = publish_; }
285 
286 		bool PublishSave(int saveID)
287 		{
288 			notifyStatus(String::Build("Publishing save [", saveID, "]"));
289 			if (Client::Ref().PublishSave(saveID) != RequestOkay)
290 				return false;
291 			return true;
292 		}
293 
294 		bool UnpublishSave(int saveID)
295 		{
296 			notifyStatus(String::Build("Unpublishing save [", saveID, "]"));
297 			if (Client::Ref().UnpublishSave(saveID) != RequestOkay)
298 				return false;
299 			return true;
300 		}
301 
302 		bool doWork() override
303 		{
304 			bool ret;
305 			for (size_t i = 0; i < saves.size(); i++)
306 			{
307 				if (publish)
308 					ret = PublishSave(saves[i]);
309 				else
310 					ret = UnpublishSave(saves[i]);
311 				if (!ret)
312 				{
313 					if (publish) // uses html page so error message will be spam
314 						notifyError(String::Build("Failed to publish [", saves[i], "], is this save yours?"));
315 					else
316 						notifyError(String::Build("Failed to unpublish [", saves[i], "]: " + Client::Ref().GetLastError()));
317 					c->Refresh();
318 					return false;
319 				}
320 				notifyProgress((float(i+1)/float(saves.size())*100));
321 			}
322 			c->Refresh();
323 			return true;
324 		}
325 	};
326 
327 	std::vector<int> selected = searchModel->GetSelected();
328 	new TaskWindow(publish ? String("Publishing Saves") : String("Unpublishing Saves"), new UnpublishSavesTask(selected, this, publish));
329 }
330 
FavouriteSelected()331 void SearchController::FavouriteSelected()
332 {
333 	class FavouriteSavesTask : public Task
334 	{
335 		std::vector<int> saves;
336 	public:
337 		FavouriteSavesTask(std::vector<int> saves_) { saves = saves_; }
338 		bool doWork() override
339 		{
340 			for (size_t i = 0; i < saves.size(); i++)
341 			{
342 				notifyStatus(String::Build("Favouring save [", saves[i], "]"));
343 				if (Client::Ref().FavouriteSave(saves[i], true)!=RequestOkay)
344 				{
345 					notifyError(String::Build("Failed to favourite [", saves[i], "]: " + Client::Ref().GetLastError()));
346 					return false;
347 				}
348 				notifyProgress((float(i+1)/float(saves.size())*100));
349 			}
350 			return true;
351 		}
352 	};
353 
354 	class UnfavouriteSavesTask : public Task
355 	{
356 		std::vector<int> saves;
357 	public:
358 		UnfavouriteSavesTask(std::vector<int> saves_) { saves = saves_; }
359 		bool doWork() override
360 		{
361 			for (size_t i = 0; i < saves.size(); i++)
362 			{
363 				notifyStatus(String::Build("Unfavouring save [", saves[i], "]"));
364 				if (Client::Ref().FavouriteSave(saves[i], false)!=RequestOkay)
365 				{
366 					notifyError(String::Build("Failed to unfavourite [", saves[i], "]: " + Client::Ref().GetLastError()));
367 					return false;
368 				}
369 				notifyProgress((float(i+1)/float(saves.size())*100));
370 			}
371 			return true;
372 		}
373 	};
374 
375 	std::vector<int> selected = searchModel->GetSelected();
376 	if (!searchModel->GetShowFavourite())
377 		new TaskWindow("Favouring saves", new FavouriteSavesTask(selected));
378 	else
379 		new TaskWindow("Unfavouring saves", new UnfavouriteSavesTask(selected));
380 	ClearSelection();
381 }
382