1 | // Aseprite |
---|---|
2 | // Copyright (C) 2019-2022 Igara Studio S.A. |
3 | // Copyright (C) 2001-2018 David Capello |
4 | // |
5 | // This program is distributed under the terms of |
6 | // the End-User License Agreement for Aseprite. |
7 | |
8 | #ifdef HAVE_CONFIG_H |
9 | #include "config.h" |
10 | #endif |
11 | |
12 | #include "app/ui/home_view.h" |
13 | |
14 | #include "app/app.h" |
15 | #include "app/app_menus.h" |
16 | #include "app/commands/commands.h" |
17 | #include "app/commands/params.h" |
18 | #include "app/crash/data_recovery.h" |
19 | #include "app/i18n/strings.h" |
20 | #include "app/ui/data_recovery_view.h" |
21 | #include "app/ui/main_window.h" |
22 | #include "app/ui/recent_listbox.h" |
23 | #include "app/ui/skin/skin_theme.h" |
24 | #include "app/ui/status_bar.h" |
25 | #include "app/ui/workspace.h" |
26 | #include "app/ui/workspace_tabs.h" |
27 | #include "app/ui_context.h" |
28 | #include "base/exception.h" |
29 | #include "fmt/format.h" |
30 | #include "ui/label.h" |
31 | #include "ui/resize_event.h" |
32 | #include "ui/system.h" |
33 | #include "ui/textbox.h" |
34 | #include "ui/view.h" |
35 | #include "ver/info.h" |
36 | |
37 | #ifdef ENABLE_NEWS |
38 | #include "app/ui/news_listbox.h" |
39 | #endif |
40 | |
41 | #if ENABLE_SENTRY |
42 | #include "app/sentry_wrapper.h" |
43 | #endif |
44 | |
45 | #ifdef ENABLE_DRM |
46 | #include "drm/drm.h" |
47 | #include "aseprite_update.h" |
48 | #endif |
49 | |
50 | namespace app { |
51 | |
52 | using namespace ui; |
53 | using namespace app::skin; |
54 | |
55 | HomeView::HomeView() |
56 | : m_files(new RecentFilesListBox) |
57 | , m_folders(new RecentFoldersListBox) |
58 | #ifdef ENABLE_NEWS |
59 | , m_news(new NewsListBox) |
60 | #endif |
61 | , m_dataRecovery(App::instance()->dataRecovery()) |
62 | , m_dataRecoveryView(nullptr) |
63 | { |
64 | newFile()->Click.connect([this]{ onNewFile(); }); |
65 | openFile()->Click.connect([this]{ onOpenFile(); }); |
66 | if (m_dataRecovery) |
67 | recoverSprites()->Click.connect([this]{ onRecoverSprites(); }); |
68 | else |
69 | recoverSprites()->setVisible(false); |
70 | |
71 | filesView()->attachToView(m_files); |
72 | foldersView()->attachToView(m_folders); |
73 | #ifdef ENABLE_NEWS |
74 | newsView()->attachToView(m_news); |
75 | #endif |
76 | |
77 | checkUpdate()->setVisible(false); |
78 | shareCrashdb()->setVisible(false); |
79 | |
80 | #if ENABLE_SENTRY |
81 | // Show this option in home tab only when we require consent for the |
82 | // first time and there is crash data available to report |
83 | if (Sentry::requireConsent() && |
84 | Sentry::areThereCrashesToReport()) { |
85 | shareCrashdb()->setVisible(true); |
86 | shareCrashdb()->Click.connect( |
87 | [this]{ |
88 | if (shareCrashdb()->isSelected()) |
89 | Sentry::giveConsent(); |
90 | else |
91 | Sentry::revokeConsent(); |
92 | }); |
93 | } |
94 | #endif |
95 | |
96 | InitTheme.connect( |
97 | [this]{ |
98 | auto theme = SkinTheme::get(this); |
99 | setBgColor(theme->colors.workspace()); |
100 | setChildSpacing(8 * guiscale()); |
101 | }); |
102 | initTheme(); |
103 | } |
104 | |
105 | HomeView::~HomeView() |
106 | { |
107 | #ifdef ENABLE_DATA_RECOVERY |
108 | if (m_dataRecoveryView) { |
109 | ASSERT(!m_dataRecoveryView->parent()); |
110 | delete m_dataRecoveryView; |
111 | } |
112 | #endif |
113 | } |
114 | |
115 | void HomeView::dataRecoverySessionsAreReady() |
116 | { |
117 | #ifdef ENABLE_DATA_RECOVERY |
118 | |
119 | #ifdef ENABLE_TRIAL_MODE |
120 | DRM_INVALID{ |
121 | return; |
122 | } |
123 | #endif |
124 | |
125 | if (App::instance()->dataRecovery()->hasRecoverySessions()) { |
126 | // We highlight the "Recover Files" options because we came from a crash |
127 | auto theme = SkinTheme::get(this); |
128 | recoverSprites()->setStyle(theme->styles.workspaceUpdateLink()); |
129 | layout(); |
130 | } |
131 | if (m_dataRecoveryView) { |
132 | m_dataRecoveryView->refreshListNotification(); |
133 | } |
134 | #endif |
135 | } |
136 | |
137 | #if ENABLE_SENTRY |
138 | void HomeView::updateConsentCheckbox() |
139 | { |
140 | if (Sentry::requireConsent()) { |
141 | shareCrashdb()->setVisible(true); |
142 | shareCrashdb()->setSelected(false); |
143 | } |
144 | else if (Sentry::consentGiven()) { |
145 | shareCrashdb()->setVisible(false); |
146 | shareCrashdb()->setSelected(true); |
147 | } |
148 | layout(); |
149 | } |
150 | #endif |
151 | |
152 | std::string HomeView::getTabText() |
153 | { |
154 | return Strings::home_view_title(); |
155 | } |
156 | |
157 | TabIcon HomeView::getTabIcon() |
158 | { |
159 | return TabIcon::HOME; |
160 | } |
161 | |
162 | gfx::Color HomeView::getTabColor() |
163 | { |
164 | return gfx::ColorNone; |
165 | } |
166 | |
167 | bool HomeView::onCloseView(Workspace* workspace, bool quitting) |
168 | { |
169 | workspace->removeView(this); |
170 | return true; |
171 | } |
172 | |
173 | void HomeView::onAfterRemoveView(Workspace* workspace) |
174 | { |
175 | if (m_dataRecoveryView && |
176 | m_dataRecoveryView->parent()) { |
177 | workspace->removeView(m_dataRecoveryView); |
178 | } |
179 | } |
180 | |
181 | void HomeView::onTabPopup(Workspace* workspace) |
182 | { |
183 | Menu* menu = AppMenus::instance()->getTabPopupMenu(); |
184 | if (!menu) |
185 | return; |
186 | |
187 | menu->showPopup(mousePosInDisplay(), display()); |
188 | } |
189 | |
190 | void HomeView::onWorkspaceViewSelected() |
191 | { |
192 | StatusBar::instance()->showDefaultText(); |
193 | } |
194 | |
195 | void HomeView::onNewFile() |
196 | { |
197 | Command* command = Commands::instance()->byId(CommandId::NewFile()); |
198 | UIContext::instance()->executeCommandFromMenuOrShortcut(command); |
199 | } |
200 | |
201 | void HomeView::onOpenFile() |
202 | { |
203 | Command* command = Commands::instance()->byId(CommandId::OpenFile()); |
204 | UIContext::instance()->executeCommandFromMenuOrShortcut(command); |
205 | } |
206 | |
207 | void HomeView::onResize(ui::ResizeEvent& ev) |
208 | { |
209 | headerPlaceholder()->setVisible(ev.bounds().h > 200*ui::guiscale()); |
210 | foldersPlaceholder()->setVisible(ev.bounds().h > 150*ui::guiscale()); |
211 | #ifdef ENABLE_NEWS |
212 | newsPlaceholder()->setVisible(ev.bounds().w > 200*ui::guiscale()); |
213 | #else |
214 | newsPlaceholder()->setVisible(false); |
215 | #endif |
216 | |
217 | ui::VBox::onResize(ev); |
218 | } |
219 | |
220 | #ifdef ENABLE_UPDATER |
221 | |
222 | void HomeView::onCheckingUpdates() |
223 | { |
224 | checkUpdate()->setText(Strings::home_view_checking_updates()); |
225 | checkUpdate()->setVisible(true); |
226 | |
227 | layout(); |
228 | } |
229 | |
230 | void HomeView::onUpToDate() |
231 | { |
232 | checkUpdate()->setVisible(false); |
233 | |
234 | layout(); |
235 | } |
236 | |
237 | void HomeView::onNewUpdate(const std::string& url, const std::string& version) |
238 | { |
239 | checkUpdate()->setText( |
240 | fmt::format(Strings::home_view_new_version_available(), |
241 | get_app_name(), version)); |
242 | #ifdef ENABLE_DRM |
243 | DRM_INVALID { |
244 | checkUpdate()->setUrl(url); |
245 | } |
246 | else { |
247 | checkUpdate()->setUrl(""); |
248 | checkUpdate()->Click.connect([version] { |
249 | app::AsepriteUpdate dlg(version); |
250 | dlg.openWindowInForeground(); |
251 | }); |
252 | } |
253 | #else |
254 | checkUpdate()->setUrl(url); |
255 | #endif |
256 | checkUpdate()->setVisible(true); |
257 | checkUpdate()->InitTheme.connect( |
258 | [this]{ |
259 | auto theme = SkinTheme::get(this); |
260 | checkUpdate()->setStyle(theme->styles.workspaceUpdateLink()); |
261 | }); |
262 | checkUpdate()->initTheme(); |
263 | |
264 | layout(); |
265 | } |
266 | |
267 | #endif // ENABLE_UPDATER |
268 | |
269 | void HomeView::onRecoverSprites() |
270 | { |
271 | #ifdef ENABLE_DATA_RECOVERY |
272 | |
273 | #ifdef ENABLE_TRIAL_MODE |
274 | DRM_INVALID{ |
275 | return; |
276 | } |
277 | #endif |
278 | |
279 | ASSERT(m_dataRecovery); // "Recover Files" button is hidden when |
280 | // data recovery is disabled (m_dataRecovery == nullptr) |
281 | if (!m_dataRecovery) |
282 | return; |
283 | |
284 | if (!m_dataRecoveryView) { |
285 | m_dataRecoveryView = new DataRecoveryView(m_dataRecovery); |
286 | |
287 | // Restore the "Recover Files" link style when the |
288 | // DataRecoveryView is empty (so there is no more warning icon on |
289 | // it). |
290 | m_dataRecoveryView->Empty.connect( |
291 | [this]{ |
292 | auto theme = SkinTheme::get(this); |
293 | recoverSprites()->setStyle(theme->styles.workspaceLink()); |
294 | layout(); |
295 | }); |
296 | } |
297 | |
298 | if (!m_dataRecoveryView->parent()) |
299 | App::instance()->workspace()->addView(m_dataRecoveryView); |
300 | |
301 | App::instance()->mainWindow()->getTabsBar()->selectTab(m_dataRecoveryView); |
302 | #endif |
303 | } |
304 | |
305 | } // namespace app |
306 |