| 1 | // Copyright © SixtyFPS GmbH <info@slint.dev> |
| 2 | // SPDX-License-Identifier: MIT |
| 3 | |
| 4 | import { GroupBox, ComboBox, VerticalBox, GroupBox, GridBox, Palette, TextEdit, Button, Switch, ScrollView, StyleMetrics } from "std-widgets.slint" ; |
| 5 | import { NavigationListView, NavigationListViewItem, Container, ExtendedLineEdit, Icon, CardListView, CardListViewItem, IconButton, TitleText } from "../widgets.slint" ; |
| 6 | import { ModalDialog } from "../widgets.slint" ; |
| 7 | import { Icons } from "../assets.slint" ; |
| 8 | import { UsecasesPalette } from "../widgets/styling.slint" ; |
| 9 | import { DialogGlobal } from "../widgets/dialog.slint" ; |
| 10 | |
| 11 | export global MailViewAdapter { } |
| 12 | |
| 13 | export global MailSideBarViewAdapter { |
| 14 | out property <[string]> accounts: ["jon.doe@slint.dev" , "jon.doe@my-mail.com" , "jon.doe@gmail.com" ]; |
| 15 | |
| 16 | out property <[NavigationListViewItem]> boxes: [ |
| 17 | { text: @tr("Inbox" ), message: "128" , icon: Icons.inbox }, |
| 18 | { text: @tr("Drafts" ), message: "9" , icon: Icons.document }, |
| 19 | { text: @tr("Sent" ), icon: Icons.send }, |
| 20 | { |
| 21 | text: @tr("Junk" ), |
| 22 | icon: Icons.junk, |
| 23 | message: "23" , |
| 24 | }, |
| 25 | { text: @tr("Trash" ), icon: Icons.trash }, |
| 26 | { text: @tr("Archive" ), icon: Icons.archive } |
| 27 | ]; |
| 28 | |
| 29 | out property <[NavigationListViewItem]> custom-boxes: [ |
| 30 | { text: @tr("Social" ), message: "3972" , icon: Icons.useres }, |
| 31 | { text: @tr("Updates" ), message: "342" , icon: Icons.updates }, |
| 32 | { text: @tr("Forums" ), message: "128" , icon: Icons.message } |
| 33 | ]; |
| 34 | in-out property <int> current-box; |
| 35 | in-out property <int> current-custom-box: -1; |
| 36 | |
| 37 | public pure function current-title() -> string { |
| 38 | if current-box > -1 && current-box < boxes.length { |
| 39 | return boxes[current-box].text; |
| 40 | } |
| 41 | if current-custom-box > -1 && current-custom-box < custom-boxes.length { |
| 42 | return custom-boxes[current-custom-box].text; |
| 43 | } |
| 44 | "" |
| 45 | } |
| 46 | } |
| 47 | |
| 48 | export component MailContainer inherits Container { |
| 49 | background: UsecasesPalette.use-material ? Palette.alternate-background : Palette.control-background; |
| 50 | border-color: UsecasesPalette.use-material ? Palette.border : transparent; |
| 51 | } |
| 52 | |
| 53 | export component MailSideBarView { |
| 54 | in property <bool> break-layout; |
| 55 | |
| 56 | horizontal-stretch: 0; |
| 57 | min-width: 200px; |
| 58 | |
| 59 | VerticalLayout { |
| 60 | spacing: 4px; |
| 61 | |
| 62 | if !root.break-layout : ComboBox { |
| 63 | model: MailSideBarViewAdapter.accounts; |
| 64 | } |
| 65 | |
| 66 | Container { |
| 67 | border-radius: UsecasesPalette.use-material ? 0 : 4px; |
| 68 | |
| 69 | NavigationListView { |
| 70 | model: MailSideBarViewAdapter.boxes; |
| 71 | current-item <=> MailSideBarViewAdapter.current-box; |
| 72 | min-height: 248px; |
| 73 | vertical-stretch: 0; |
| 74 | |
| 75 | selected(index) => { |
| 76 | MailSideBarViewAdapter.current-custom-box = -1; |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | Rectangle { |
| 81 | background: Palette.border; |
| 82 | height: 1px; |
| 83 | } |
| 84 | |
| 85 | NavigationListView { |
| 86 | model: MailSideBarViewAdapter.custom-boxes; |
| 87 | current-item <=> MailSideBarViewAdapter.current-custom-box; |
| 88 | |
| 89 | selected(index) => { |
| 90 | MailSideBarViewAdapter.current-box = -1; |
| 91 | } |
| 92 | } |
| 93 | } |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | export component MailSideBarDialog inherits ModalDialog { |
| 98 | in property <length> sidebar-x; |
| 99 | in property <length> sidebar-y; |
| 100 | in property <length> sidebar-height; |
| 101 | |
| 102 | Rectangle { |
| 103 | x: root.sidebar-x - self.width; |
| 104 | y: root.sidebar-y; |
| 105 | width: 246px; |
| 106 | height: root.sidebar-height; |
| 107 | background: Palette.control-background; |
| 108 | |
| 109 | HorizontalLayout { |
| 110 | padding: UsecasesPalette.use-material ? 0 : 4px; |
| 111 | |
| 112 | side-bar := MailSideBarView { |
| 113 | width: 360px; |
| 114 | break-layout: true; |
| 115 | } |
| 116 | } |
| 117 | |
| 118 | animate x { |
| 119 | duration: 250ms; |
| 120 | easing: cubic-bezier(0, 0, 0, 1); |
| 121 | } |
| 122 | |
| 123 | init => { |
| 124 | self.x = root.sidebar-x; |
| 125 | } |
| 126 | } |
| 127 | } |
| 128 | |
| 129 | export global MailBoxViewAdapter { |
| 130 | callback search-text-changed(search-text: string); |
| 131 | |
| 132 | in property <string> title: MailSideBarViewAdapter.current-title(); |
| 133 | in property <[CardListViewItem]> mails: [ |
| 134 | { |
| 135 | title: "Simon Hausmann" , |
| 136 | note: "1 hour ago" , |
| 137 | sub-title: "Meeting tomorrow" , |
| 138 | caption: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat." |
| 139 | }, |
| 140 | { title: "Tobias Hunger" , note: "1 day ago" , sub-title: "Meeting tomorrow" , caption: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat." }, |
| 141 | { |
| 142 | title: "Olivier Goffart" , |
| 143 | note: "2 hour ago" , |
| 144 | sub-title: "Meeting tomorrow" , |
| 145 | caption: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat." |
| 146 | }, |
| 147 | { |
| 148 | title: "Aurindam Jana" , |
| 149 | note: "5 hour ago" , |
| 150 | sub-title: "Meeting tomorrow" , |
| 151 | caption: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat." |
| 152 | }, |
| 153 | { |
| 154 | title: "Simon Hausmann" , |
| 155 | note: "7 hour ago" , |
| 156 | sub-title: "Meeting tomorrow" , |
| 157 | caption: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat." |
| 158 | }, |
| 159 | { title: "Tobias Hunger" , note: "1 day ago" , sub-title: "Meeting tomorrow" , caption: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat." }, |
| 160 | { |
| 161 | title: "Olivier Goffart" , |
| 162 | note: "8 hour ago" , |
| 163 | sub-title: "Meeting tomorrow" , |
| 164 | caption: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat." |
| 165 | }, |
| 166 | { |
| 167 | title: "Aurindam Jana" , |
| 168 | note: "9 hour ago" , |
| 169 | sub-title: "Meeting tomorrow" , |
| 170 | caption: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat." |
| 171 | }, |
| 172 | ]; |
| 173 | } |
| 174 | |
| 175 | export component MailBoxView { |
| 176 | in property <bool> break-layout; |
| 177 | |
| 178 | callback show-sidebar(); |
| 179 | |
| 180 | horizontal-stretch: 1; |
| 181 | |
| 182 | VerticalLayout { |
| 183 | spacing: 4px; |
| 184 | |
| 185 | HorizontalLayout { |
| 186 | spacing: 8px; |
| 187 | |
| 188 | if root.break-layout : IconButton { |
| 189 | icon: Icons.menu; |
| 190 | |
| 191 | clicked => { |
| 192 | root.show-sidebar(); |
| 193 | } |
| 194 | } |
| 195 | |
| 196 | TitleText { |
| 197 | text: MailBoxViewAdapter.title; |
| 198 | min-height: 32px; |
| 199 | } |
| 200 | } |
| 201 | |
| 202 | MailContainer { |
| 203 | VerticalLayout { |
| 204 | spacing: 8px; |
| 205 | |
| 206 | ExtendedLineEdit { |
| 207 | vertical-stretch: 0; |
| 208 | placeholder-text: "Search by Sender" ; |
| 209 | |
| 210 | Icon { |
| 211 | source: Icons.search; |
| 212 | } |
| 213 | |
| 214 | edited => { |
| 215 | MailBoxViewAdapter.search-text-changed(self.text); |
| 216 | } |
| 217 | } |
| 218 | |
| 219 | CardListView { |
| 220 | model: MailBoxViewAdapter.mails; |
| 221 | } |
| 222 | } |
| 223 | } |
| 224 | } |
| 225 | } |
| 226 | |
| 227 | export global MailMessageViewAdapter { |
| 228 | callback move-to-archive(); |
| 229 | callback move-to-junk(); |
| 230 | callback move-to-trash(); |
| 231 | callback reply(); |
| 232 | callback forward(); |
| 233 | callback send(); |
| 234 | |
| 235 | in property <string> message: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat." ; |
| 236 | in-out property <bool> mute-this-thread: false; |
| 237 | } |
| 238 | |
| 239 | export component MailMessageView { |
| 240 | horizontal-stretch: 1; |
| 241 | |
| 242 | MailContainer { |
| 243 | HorizontalLayout { |
| 244 | spacing: 8px; |
| 245 | |
| 246 | IconButton { |
| 247 | icon: Icons.archive; |
| 248 | |
| 249 | clicked => { |
| 250 | MailMessageViewAdapter.move-to-archive(); |
| 251 | } |
| 252 | } |
| 253 | |
| 254 | IconButton { |
| 255 | icon: Icons.junk; |
| 256 | |
| 257 | clicked => { |
| 258 | MailMessageViewAdapter.move-to-junk(); |
| 259 | } |
| 260 | } |
| 261 | |
| 262 | IconButton { |
| 263 | icon: Icons.trash; |
| 264 | |
| 265 | clicked => { |
| 266 | MailMessageViewAdapter.move-to-trash(); |
| 267 | } |
| 268 | } |
| 269 | |
| 270 | Rectangle {} |
| 271 | |
| 272 | IconButton { |
| 273 | icon: Icons.reply; |
| 274 | |
| 275 | clicked => { |
| 276 | MailMessageViewAdapter.reply(); |
| 277 | } |
| 278 | } |
| 279 | |
| 280 | IconButton { |
| 281 | icon: Icons.forward; |
| 282 | |
| 283 | clicked => { |
| 284 | MailMessageViewAdapter.forward(); |
| 285 | } |
| 286 | } |
| 287 | } |
| 288 | |
| 289 | VerticalLayout { |
| 290 | spacing: 4px; |
| 291 | |
| 292 | text-edit := TextEdit { |
| 293 | min-height: 52px; |
| 294 | max-height: 94px; |
| 295 | wrap: word-wrap; |
| 296 | } |
| 297 | |
| 298 | ScrollView { |
| 299 | VerticalLayout { |
| 300 | x: 0; |
| 301 | y: 0; |
| 302 | |
| 303 | mail-text := Text { |
| 304 | vertical-alignment: top; |
| 305 | font-size: 14px; |
| 306 | font-weight: 400; |
| 307 | color: Palette.foreground; |
| 308 | text: MailMessageViewAdapter.message; |
| 309 | wrap: word-wrap; |
| 310 | } |
| 311 | } |
| 312 | } |
| 313 | |
| 314 | HorizontalLayout { |
| 315 | Switch { |
| 316 | text: @tr("Mute this thread" ); |
| 317 | checked <=> MailMessageViewAdapter.mute-this-thread; |
| 318 | } |
| 319 | |
| 320 | Button { |
| 321 | text: @tr("Send" ); |
| 322 | primary: true; |
| 323 | enabled: text-edit.text != "" ; |
| 324 | |
| 325 | clicked => { |
| 326 | MailMessageViewAdapter.send(); |
| 327 | } |
| 328 | } |
| 329 | } |
| 330 | } |
| 331 | } |
| 332 | } |
| 333 | |
| 334 | export component MailView { |
| 335 | in property <bool> break-layout; |
| 336 | |
| 337 | HorizontalLayout { |
| 338 | spacing: 16px; |
| 339 | |
| 340 | if !root.break-layout: MailSideBarView { } |
| 341 | |
| 342 | VerticalLayout { |
| 343 | spacing: 16px; |
| 344 | |
| 345 | MailBoxView { |
| 346 | break-layout: root.break-layout; |
| 347 | |
| 348 | show-sidebar => { |
| 349 | sidebar-dialog.show(); |
| 350 | } |
| 351 | } |
| 352 | |
| 353 | MailMessageView { } |
| 354 | } |
| 355 | } |
| 356 | |
| 357 | sidebar-dialog := MailSideBarDialog { |
| 358 | sidebar-x: 0; |
| 359 | sidebar-y: root.absolute-position.y; |
| 360 | sidebar-height: DialogGlobal.window-height - root.absolute-position.y; |
| 361 | } |
| 362 | } |
| 363 | |