Compare commits

..
Author SHA1 Message Date
Alexandra Betouni 0cbdea5d73 feat(StatusTagSelector): fixed admin / non admin permissions
Needed for: status-im/status-desktop#5941
2022-09-08 18:55:37 +03:00
Lukáš Tinkl 384924ce58 fix: StatusDateGroupLabel doesn't support i18n and has no year
- fix evaluating "Today" and "Yesterday"; can't just compare the two Date
objects, the timestamp will always differ so need to compare
year/month/day only
- best attempt to have the month translated, and year added if they
differ (until Qt6 at least, left a TODO)

Closes #843
2022-09-08 13:21:01 +02:00
Sale Djenic 8c683bf83c feat(Controls): introduce StatusPasswordInput
`StatusPasswordInput` is a wrapper around  `TextField` with an option
to display signing phrase.
2022-09-08 13:03:04 +02:00
Michał f6424328d8 feat(StatusItemSelector): improved reusablity, addItem and popup handling removed (#887)
Additionally:
- minor positioning fixes in StatusListItem and StatusListItemTag
- StatusItemSelectorPage updated and added to main.qml
2022-09-08 11:06:25 +02:00
PavelS 60137c39b5 fix(StatusListItem): adjust placement of title icons (#888)
Needed for https://github.com/status-im/status-desktop/issues/6972
2022-09-07 19:28:52 +03:00
Pascal Precht 4d16ac17a8 fix(StatusBaseButton): fix wrong id usage 2022-09-07 15:15:05 +02:00
Pascal Precht 504053a6bf fix(StatusBaseButton): keep MouseArea enabled when in loading state
`StatusBaseButton` comes with a `MouseArea` that is disabled when the
button is set to being disabled. Prior to this commit it's *also* disabled
when the button is in `loading` state.

This makes sense because a button that is in `loading` state shouldn't
not emit any click signals or trigger hover indications.

There's a scenario though in which we want render a tooltip on top of
the button which is in `loading` state. For the tooltip to show, the
`MouseArea` of the button needs to be enabled.

Hence, this commit adjust `StatusBaseButton`'s behaviour to *not*
disable the `MouseArea` when it's `loading`. Mouse events are already
prevented via the `loading` flag. So the only thing left to do is to
ensure the button doesn't trigger any hover indication when in `loading`
state.
2022-09-07 13:49:18 +02:00
Pascal Precht fc10a0d43d feat(StatusMessageReply): introduce profileClickable property
This is analogue to `profileClickable` available on `StatusMessage`,
preventing users to activate a reply-to-message's profile avatar.

At the time of this commit, this is only the case for imported messages.
So we can derive that, if `StatusMessage.profileClickable` is false, then
`StatusMessageReply.profileClickable` is also false.

Hence, we don't need to expose this property to higher level APIs.
2022-09-06 11:24:19 +02:00
Stefan 3b6a6067af fix(StatusSelect): set implicitWidth to the content size 2022-09-05 12:14:56 +02:00
Patryk Osmaczko f1d7bdb069 fix(StatusTagSelector): forbid removing readonly tags 2022-09-05 12:06:28 +02:00
Lukáš Tinkl 32db0bb023 fix(StatusRadioButton): StatusRadioButton can't be fully clicked
- fix the control's width (don't have to be explicit, the QQC2 Control
takes care of calculating the implicitWidth/Height automatically based on
contents)
- while at it, fix the metrics to be able to support RTL
languages too (it was off for Arabic)
- some smaller cleanups too
2022-09-05 09:35:20 +02:00
Lukáš Tinkl 9688113d7f fix: remove duplicate entries 2022-09-05 09:35:20 +02:00
Alexandra Betouni 98d0d2163e feat(StatusQ): Merging Icon, Background and Image Settings (#788)
Closes #781
2022-09-02 18:40:30 +03:00
Alexandra Betouni e146ccaed4 fix(StatusScrollBar): Fixed visibilty when policy always on (#878)
Needed for https://github.com/status-im/status-desktop/issues/6262
2022-09-02 15:49:08 +03:00
PavelS 5e7a0d8251 fix(StatusSelectableText): add missing Utils import (#880) 2022-09-02 14:51:16 +03:00
Alexandra Betouni ecc44cfae0 feat(StatusQ/Layout)!: Cleaning up Layouts for consistency (#836)
- Created StatusMainLayout to be used as the apps' main
  layout
- Created StatusSectionLayout to be used for all sections as
  their base
  - Created StatusToolBar as part of StatusAppLayout with
    standard component the ActivityButton and posibility to
    add custom implementation components

Needed for https://github.com/status-im/status-desktop/issues/6635
2022-09-02 10:25:43 +03:00
Pascal Precht ad8bc322d1 feat(StatusMessage): introduce profileClickable property
This property allows for enabling/disabling whether or not the profile
picture and display name of a message is clickable and also dictates the
cursor type accordingly.

The reason this is being introduced is that, with imported messages from
other systems (e.g. discord, telegram etc), we don't want the user to
trigger the popup menu for more profile information because we don't
know any profile information of messages coming from such systems.

Such messages are signed by the community.

Closes https://github.com/status-im/status-desktop/issues/6680
2022-09-01 14:40:25 +02:00
PavelS 80a9cc9b3f feat(Icons): add quote icon (#876)
Needed for https://github.com/status-im/status-desktop/issues/6988
2022-08-31 17:43:12 +03:00
Michał 803a7637bf fix(StatusImageCropPanel): display SizeAllCursor cursor when over image (#864) 2022-08-31 15:36:23 +02:00
MishkaRogachev 4d9cec541f fix(StatusChatListCategory): Add alias to category item for squish tests 2022-08-31 14:29:35 +03:00
PavelS 4d73c25c7a feat(StatusScrollView): add ensureVisible function to Utils (#868)
Replace local ensureVisible with ensureVisible function from Utils

Required for https://github.com/status-im/status-desktop/issues/7093
2022-08-31 11:19:20 +03:00
Michał 8646daa401 chore(StatusAppNavBar): List views' bounds behavior refined (#866)
- outer list: not draggable
- communities list: not draggable when sufficient space,
  drag and overshot otherwise
2022-08-26 18:04:17 +02:00
Noelia db0f8e9fb5 feat(StatusItemPicker): Added radioButtonSize property
Added properties `namePixelSize` and `radioButtonSize`.
Some fixes when shortName is undefined.
2022-08-26 17:27:02 +02:00
Noelia 9d6cea7051 feat(StatusRadioButton): Added size variant Large and Small 2022-08-26 17:27:02 +02:00
Pascal Precht 780ade987d feat(StatusMessage): add messageOriginInfo property
This is a property that allows for adding information about the origin
of a message (e.g. "Imported from discord").

This will most likely be only useful for messages that have been
imported from any other platform.

Because importing from other platforms requires those message to be
signed by a Status Account, it's undesirable to render the public key of
the account that signed imported messages.

Hence, when there's a `messageOriginInfo`, we don't render the elided
public key.
2022-08-26 13:11:19 +02:00
Igor Sirotin fd6d735df8 test(StatusMessage): Added objectName to StatusTextMessage (#869) 2022-08-25 23:30:05 +03:00
Jonathan Rainville 4d63af303c test(StatusChatInfoButton): add objectName to pin text for tests 2022-08-24 10:08:17 -04:00
Jonathan Rainville 1e12636abd test(StatusTextMessage): add objectName for test 2022-08-22 13:48:24 -04:00
Michał 89049fd56b fix(StatusTabButton): display hand cursor on hover when enabled (#859)
Needed for https://github.com/status-im/status-desktop/issues/6787
2022-08-22 14:35:36 +02:00
Michal Iskierko be24401a50 fix(Theme): Adding additional green color
Issue #6279
2022-08-22 13:44:40 +02:00
Stefan 8214e64684 fix(StatusChatListCategory): Clicking on a category should toggle it
The culprit here is at the very bottom, in StatusListItem: the toplevel
item was a MouseArea handling the clicks and this causes problems as any
extra buttons placed on top of it get their mouseClick events delivered
in wrong order (after StatusListItem). Fix this by having a MouseArea
handling click events behind the actual toplevel item as a last resort,
catch all handler  plus the actual "sensor" being just a MouseArea that
handles merely the hover events

- drop unneeded onPressed/onReleased handlers in StatusChatListCategoryItem
- fix some warnings (typos, unreachable code, shadowed variables)

Fixes: #6733
2022-08-22 12:29:24 +02:00
Stefan 50299f8d83 test(Sandbox): extend sandbox test for StatusChatListCategoryItem
Scope was to validate why StatusChatListCategoryItem miss behaves when
used in StatusChatListCategory.

On its own all the events works fine, as it can be seen by monitoring
the click events for each item (title, item and buttons).
However, inside StatusChatListCategory the mouse events are overlapped and
button events trigger also for the item. Tried obvious fiexes like
disabling steal of mouse events from buttons but this break the hovering
effect.

Updates: #6733
2022-08-22 12:29:24 +02:00
PavelS 6e93b4ec41 fix(CreateChatView): adjust start chat page (#863)
Add fix from https://github.com/status-im/status-desktop/pull/7077 to
demoapp
2022-08-22 10:35:23 +03:00
Igor Sirotin 6c107b5760 fix(StatusMessage): Design update and minor improvements (#752) 2022-08-20 03:01:28 +03:00
Sale Djenic a9c0c88101 feat: added missing icons
The following icons added:
- `key_pair_prvate_key.svg`
- `key_pair_seed_phrase.svg`
2022-08-18 16:40:58 +02:00
Sale Djenic b59295d56b feat(StatusListItem): scroll feature added if list of tags exceeds component width 2022-08-18 16:40:58 +02:00
Jonathan Rainville b9882c6ff6 test(StatusSearchPopup): add object name for tests 2022-08-18 09:12:11 -04:00
Igor Sirotin 72750ef60c fix(StatusComboBox): Pointing hand cursor on hover (#862) 2022-08-18 15:07:16 +03:00
PavelS 9f6f9905e9 fix(StatusInput)!: trigger errors bindings (#858)
Change valid to false by default

Fixes https://github.com/status-im/status-desktop/issues/6825

BREAKING CHANGE: StatusInput now emits signal for errors change and is
invalid by default
2022-08-18 14:45:38 +03:00
Anthony Laibe a22d8252b1 feat(@StatusComboBox): expose inner objectName property (#850) 2022-08-18 10:55:09 +02:00
Jonathan Rainville 02bb67a266 test(StatusSearchPopup): add object names for tests 2022-08-16 09:35:19 -04:00
Stefan f15b0d4de4 fix(StatusChatListAndCategories): duplicate objectName
Due to repository automerge.
2022-08-16 11:47:47 +02:00
Stefan 8f06729c1a tests(StatusChatListAndCategories.qml) add object names for testing 2022-08-16 11:30:06 +02:00
MishkaRogachev c721a67c70 test(StatusChatListAndCategories): Add object names 2022-08-15 18:10:24 +04:00
PavelS b2e8a0e282 fix(StatusPopupMenu): update popup content to support big margins (#853)
Needed for https://github.com/status-im/status-desktop/issues/6822
2022-08-15 16:48:58 +03:00
PavelS 76cc5fda22 fix(StatusMenuItemDelegate): adjust menu item height (#852)
Needed for https://github.com/status-im/status-desktop/issues/6830
2022-08-15 12:53:44 +03:00
Sale Djenic e1d8d934b3 feat(StatusCheckbox): introduced new leftSide prop
- `leftSide` determines whether to display check box on the left or right
side, defaulted to left
2022-08-11 13:20:17 +02:00
Khushboo-dev-cpp 9fa6fb2324 fix(StatusColorSelectorGrid): Expose the Color Repeater for Squish testing (#847) 2022-08-11 12:58:09 +02:00
Patryk Osmaczko ce22d8759c fix(StatusIconTextButton): make icon invisible when no icon is loaded
Otherwise this button has invisible left padding when no icon is set
2022-08-10 14:43:28 +02:00
Patryk Osmaczko 91cafca41f fix(StatusToolTip): remove contentItem by id usage
Otherwise contentItem can't be safely overriden by the clients
2022-08-10 14:43:28 +02:00
Patryk Osmaczko 151097e466 feat: add social link icons 2022-08-10 14:43:28 +02:00
PavelS 7fc207f75f fix(StatusImageCropPanel) add margins to crop area (#848)
Needed for status-im/status-desktop#6835

Required by status-im/status-desktop#6872
2022-08-10 13:58:52 +03:00
MishkaRogachev caaa2fc53b fix(StatusCommunityTags): fix width calculation 2022-08-10 12:07:32 +03:00
PavelS 98aa6a4b27 fix(StatusTabButton) adjust tab button height (#842)
Needed by https://github.com/status-im/status-desktop/issues/6786
2022-08-09 18:27:15 +03:00
Lukáš Tinkl b3ceb0aad9 feat/(Status[Base]Button): add a new Primary variant
we were missing this variant, needed for status-im/status-desktop#6081
2022-08-09 10:53:27 +02:00
Lukáš Tinkl fa16c32316 chore(Palette): do not define font properties twice
sue a shared impl, they are common to both light/dark palettes
2022-08-09 10:53:27 +02:00
PavelS 4282cc10c4 fix(StatusImageCropPanel) adjust Image Crop component (#839)
- update StatusSlider handle and background positioning

Needed for https://github.com/status-im/status-desktop/issues/6835
2022-08-09 09:54:19 +03:00
Stefan e5ddf28f02 fix(tests): fix building tests 2022-08-09 01:07:17 +02:00
Stefan 4937681645 fix(StatusImageCrop): fix artefacts due to offscreen caching
Fix by disabling layering, leftover from the previous approach of not
using Canvas.

Also investigate TODO regarding artefacts workaround and implement
a proper approach

Fixes: #6640
2022-08-09 01:07:17 +02:00
Lukáš Tinkl 39b1bcfe6b hotfix(StatusDatePicker): fix some UI issues
- make selectedDate read/write for preselecting the date
- minor toolbar spacing/sizing fixes
2022-08-08 23:20:41 +02:00
Michał 56f36ed627 fix(StatusSeedPhraseInput): fix notifying inserting word done (#841) 2022-08-08 17:38:43 +02:00
Lukáš Tinkl 789b773649 feat(StatusDatePicker): introduce StatusDatePicker component
nothing fancy, just a combo box with a calendar popup; needed for the
discord import tool UI

Related to status-im/status-desktop#6081
2022-08-08 15:05:12 +02:00
MishkaRogachev ad962a6009 fix(StatusInput): Add labelPadding customization and improve height calculation 2022-08-08 15:58:31 +03:00
MishkaRogachev f09565a4fa fix(StatusBaseInput): placeholder text is also can be multiline 2022-08-08 14:20:20 +03:00
MishkaRogachev d08339a7b0 fix(StatusStackView): Use availableWidth for content 2022-08-08 14:20:20 +03:00
Michal Iskierko 5c24767310 feat(StatusColorRadioButton): expose radio button diameter property
Issue #5982
2022-08-08 10:29:12 +02:00
Jonathan Rainville 737b9cfb3f fix(StatusChatList): fix wrong id used 2022-08-05 15:57:24 -04:00
Stefan 10d312ec8f feature(StatusAddressPanel): Implement generic address display control
Provides frame, prefix icon and copy operation int addition to StatusAddress

Updates: #6798
2022-08-05 17:01:25 +02:00
PavelS 2a377533f8 fix(StatusImageCropPanel) vertically align slider in ImageCropPanel (#829)
- change StatusSlider to be vertically centered

Needed for https://github.com/status-im/status-desktop/issues/6725
2022-08-05 16:53:55 +03:00
Boris Melnik 25e3c5526a fix(handler): Remove handler include from sandbox (#834) 2022-08-05 12:21:34 +03:00
Michał 94e59e1bf0 chore(StatusChatList): Keep sync with underlying model after reordering (#825) 2022-08-04 21:52:56 +02:00
Alexandra Betouni 3ac0187923 fix(StatusBaseInput): added left margin between text and left component (#830)
Needed for https://github.com/status-im/status-desktop/issues/6730
2022-08-04 18:03:33 +03:00
Michał a563687bf5 chore(StatusChatList)!: Use SortFilterProxyModel instead of filtering functions (#823)
BREAKING CHANGE: StatusChatList has no longer filterFn, model is
intended to be already filtered externally
2022-08-04 14:52:12 +02:00
Boris Melnik 40992f6718 feat(hot reloading): Add first version of hot reloading (#674)
Version for: https://github.com/status-im/status-desktop/issues/5690
2022-08-04 13:54:13 +03:00
Anthony Laibe 9738890d9d feat(@StatusAppNavBar): Add qr scan button 2022-08-04 09:45:59 +02:00
Jonathan Rainville 9dc2b10448 test(StatusSmartIdenticon): add objectName for tests 2022-08-04 09:45:25 +02:00
Alexandra Betouni 9df658a574 feat(StatusQ/Controls): introducing StatusBackButton
Closes: https://github.com/status-im/status-desktop/issues/6727
2022-08-03 20:41:24 +02:00
Boris Melnik 4b4b0950a6 fix(StatusSearchPopup): Fix forceActiveFocus method (#818) 2022-08-03 18:15:50 +03:00
Alexandra Betouni 7b047a4b26 fix(StatusInput): setting default 44px in min/max height (#817) 2022-08-03 16:04:52 +03:00
Igor Sirotin cff836280f Reimplemented components using StatusComboBox (#815)
* fix(StatusAccountSelector): Refactored and reimplemented using `StatusComboBox`
* fix(StatusAssetSelector): Refactored and reimplemented using `StatusComboBox`
* fix(StatusColorSelector): Reimplemented using `StatusComboBox`
* fix(StatusCardPage): Replaced `StatusSelect` with `StatusComboBox`
2022-08-03 15:13:31 +03:00
Mikhail Rogachev e432efac28 fix(StatusCommunityTag): Polish text and icon sizings (#824) 2022-08-03 12:44:35 +03:00
Alexandra Betouni 4dec615cea fix(Utils): moved emojilists.js instance inside Emoji singleton (#816)
Needed for: https://github.com/status-im/status-desktop/issues/6729
2022-08-03 11:51:38 +03:00
Khushboo-dev-cpp f4bf830ae7 feat(StatusDialog): Add DIalog Background componentto make the dialog background customizable (#809) 2022-08-03 09:27:28 +02:00
Khushboo-dev-cpp dbc0c1960a chore: Remove StatusAssetSelector from StatusQ (#806)
* fix(StatusSelect): Expose a property to make arrow in the select item visible/invisible

* chore: Remove StatusAssetSelector from StatusQ as its base component StatusSelect is enough to build this further on desktop side.

This component also has dependecy on BE and hence should be moved out.

BREAKING CHANGE:
2022-08-03 09:22:36 +02:00
Anthony Laibe 03fe75c875 feat(@StatusFloatingButtonsSelector): expose repeater (#795) 2022-08-03 09:08:47 +02:00
Patryk Osmaczko 26eaeb3ad5 chore(StatusListPicker): enable picker to work with incompatible models 2022-08-02 17:03:51 +02:00
Jonathan Rainville 462b905c5c test(StatusListItem): add objectName 2022-08-02 10:03:07 -04:00
Lukáš Tinkl 4e048f724c fix(StatusSeedPhraseInput): Back up seed phrase inputs are missing spacing
Closes: #6720
2022-08-02 13:51:58 +02:00
Lukáš Tinkl e6be4d9bad feat(StatusTextArea): Implement StatusTextArea
Implements a standard QQC2 TextArea control with Status styling

Closes #236
2022-08-02 11:35:11 +02:00
Jonathan Rainville e184348190 feat(StatusInput): add force argument to validate to force validation 2022-08-01 10:06:56 -04:00
Igor Sirotin 2270526071 feat(StatusComboBox): Introduced new component to replace StatusSelect (#790) 2022-07-30 17:45:22 +03:00
Noelia d412fe208e test(StatusTagSelector): Added objectName property needed for automation 2022-07-28 13:51:32 +02:00
Noelia 0040a2d86b test(StatusChatList): Added objectName property needed for automation 2022-07-28 13:51:32 +02:00
Noelia 431aab7bb8 test(StatusChatInfoButton): Added objectName property needed for automation 2022-07-28 13:51:32 +02:00
Alexandra Betouni 938ae6afd8 fix(StatusInput): Replaced layout spacing with margins (#808)
As part of https://github.com/status-im/status-desktop/issues/6022
2022-07-28 11:35:46 +03:00
Khushboo-dev-cpp 63c008571e fix(StatusModal): Adapt the status modal to have a user defined background color (#807)
Add a new color for StatusFloatingButtonSelector
2022-07-27 18:29:44 +02:00
Jonathan Rainville 08c53e2f52 chore(StatusScrollView): remove unused background property
BREAKING CHANGE: removes the background property of the StatusScrollView
2022-07-27 10:26:00 -04:00
Alexandra Betouni 64ec74117d fix(StatusInputPage): updated input height leftovers (#804)
As part of https://github.com/status-im/status-desktop/issues/6637
2022-07-27 16:33:55 +03:00
Patryk Osmaczko e5ab0cd2a7 chore(utils): add iconSource API to Emoji 2022-07-27 13:54:23 +02:00
Patryk Osmaczko 5f1df089eb chore(StatusListPicker): remove imperative updateInputListModel
closes: status-im/status-desktop#6500
2022-07-27 13:54:23 +02:00
Patryk Osmaczko b30f7b3ac5 chore(StatusListPicker): remove imperative filtering
iterates: status-im/status-desktop#6511, status-im/status-desktop#6500
2022-07-27 13:54:23 +02:00
Sale Djenic ac37549f62 fix(StatusSearchPopup): reset search location
New `resetSearchLocationClicked` signal introduced.

Click on `X` button is emitting `resetSearchLocationClicked` signal and
lets a component which is using this one to decide what to do instead just
reseting search selection locally to this component.

Needed for https://github.com/status-im/status-desktop/issues/6551
2022-07-26 14:37:42 +02:00
Khushboo-dev-cpp a60c44e387 Revert "chore: Remove StatusAssetSelector from StatusQ (#792)" (#805)
This reverts commit 3954d49266.
2022-07-26 14:36:26 +02:00
Mikhail Rogachev 694010da38 feat(StatusListView): Add availableWidth/availableHeight to api (#801) 2022-07-26 12:30:31 +03:00
Lukáš Tinkl c0c240ed6a hotfix(@qrc): remove the StatusAssetSelector from qrc files too
fixes the build of StatusQ/sandbox
2022-07-26 10:05:45 +02:00
Lukáš Tinkl 39c1ba4e66 fix(StatusAppNavBar): fix profile icon bottom margin
it should be 24px from the bottom according to the design
2022-07-26 10:05:45 +02:00
Khushboo-dev-cpp 3954d49266 chore: Remove StatusAssetSelector from StatusQ (#792)
* chore: Remove StatusAssetSelector from StatusQ as its base component StatusSelect is enough to build this further on desktop side.

This component also has dependecy on BE and hence should be moved out.

BREAKING CHANGE:

* fix(StatusSelect): Expose a property to make arrow in the select item visible/invisible
2022-07-25 21:16:15 +02:00
Khushboo-dev-cpp 7f99acf32d fix: Move status logo to icons folder needed in the ReceiveModal (#773) 2022-07-25 21:09:50 +02:00
Lukáš Tinkl 59b2fe4641 fix(StatusBanner): TestNet banner overlaps left panel
let the text elide on the right side if the parent width is smaller
than ours

Related: status-im/status-desktop#6600
2022-07-25 12:34:08 +02:00
Alexandra Betouni 2f650dc745 fix(StatusInput): fixing various layout issues (#794)
- Resolved binding loops in StatusInput
- Replaced all instances of StatusBaseinput
  with StatusInput
- Cleaned up min/max height properties
- Fixed total height calculation

Needed for https://github.com/status-im/status-desktop/issues/6358
2022-07-25 13:19:26 +03:00
Michał 795370086b feat(StatusChatListAndCategories) expose highlightItem property (#796) 2022-07-22 16:35:04 +02:00
Igor Sirotin c0057daa7a fix(demoapp): Replaced non-existent web images with locals (#757) 2022-07-22 16:42:05 +03:00
Michał Iskierko 08f8cd60c4 fix(StatusMinLengthValidator): Check if the text contains only whitespaces (#778)
Fixes #6304
2022-07-21 17:27:31 -04:00
Jonathan Rainville bce53e9ccc test(StatusChatToolBar): add object name for tests 2022-07-21 16:29:57 -04:00
Jonathan Rainville 930fa3daf0 test(StatusMenuItemDelegate): add objectName property for tests 2022-07-21 10:39:06 -04:00
Jonathan Rainville bc5c86a2a4 test(StatusChatInfoButton): add objectName to StatusChatInfoButton 2022-07-21 10:38:57 -04:00
Mikhail Rogachev ed6aaab441 feat(StatusListView): Add new ListView, GridView and ScrollView components with tuned scrolling
* fix(StatusScrollView): use Flickable underhood to ScrollView issues

* feat(StatusListView): New listview component without twitches

* fix(StatusScrollView): Fix background positioning and sliders visibility

* feat(StatusGridView): Add GridView wrapper
2022-07-21 16:24:37 +03:00
MishkaRogachev 442ffb9feb Fix building x86_64 solution on Mac M1 2022-07-21 15:00:11 +02:00
Sale Djenic 132cfda244 Necessary updates applied to make it work on mac 2022-07-21 15:00:11 +02:00
Patryk Osmaczko 9b89e08294 feat: add filtering&sorting example
closes: status-im/status-desktop#6510
closes: status-im/status-desktop#6512
2022-07-21 15:00:11 +02:00
Patryk Osmaczko df60ec047a chore: update README and build script 2022-07-21 15:00:11 +02:00
Patryk Osmaczko c9931f95f0 bump vendor/SortFilterProxyModel
iterates: status-im/status-desktop#6510
2022-07-21 15:00:11 +02:00
Patryk Osmaczko 6504543518 chore(git): add vendor/SortFilterProxyModel
iterates: status-im/status-desktop#6510
2022-07-21 15:00:11 +02:00
Patryk Osmaczko 9b7772be3b feat: use cmake instead of qmake
- cmake is superior to qmake (e.g. linking custom libraries)
- maintaining two build system generators is costly

iterates: status-im/status-desktop#6510
2022-07-21 15:00:11 +02:00
Alexandra Betouni 21669aba17 feat(StatusListItem): adding title text icon (#785)
Needed for https://github.com/status-im/status-desktop/issues/6494
2022-07-20 16:53:03 +03:00
Alexandra Betouni 113f700617 fix(StatusQ): Added/updated icon assets (#786)
Nedded for: https://github.com/status-im/status-desktop/issues/6494
2022-07-20 11:03:40 +03:00
Alexandra Betouni fb99107bae fix(StatusActivityCenterButton): updated offset values (#780)
Closes https://github.com/status-im/status-desktop/issues/6350
2022-07-15 19:40:00 +03:00
Alexandra Betouni 9b9b3fcfff fix(demo/CreateChatView): fixed layout issues (#783)
As part of https://github.com/status-im/status-desktop/issues/6452
2022-07-15 19:35:59 +03:00
Alexandra Betouni f19f208b3c fix(StatusBaseButton): centered button's content (#779)
Closes #724
2022-07-15 17:09:58 +03:00
Noelia 4fa885ccea refactor(StatusPickerButton): Component refactor
Component refactor to have a clean and easy-to-read code.
Unnecessary stuff removed.

BREAKING CHANGES: Removed unnecessary properties since the parent already has them.
2022-07-14 17:03:05 +02:00
Lukáš Tinkl e0fd627050 fix(SearchPopup): align with design
Needed for status-im/status-desktop#6428

- set the default icon background color to "transparent"; otherwise it
would be black when unset
- set the popup default size to 560x122 (as designed)
- add placeholder for the search field
- correct the font and icon sizes, spacing and margins according to
design
- fix some warnings
2022-07-14 14:54:26 +02:00
Lukáš Tinkl 06fad29b63 fix(StatusCheckBox): enable setting the font size
add a possibility to override the font size for the contentItem's
StatusBaseText

otherwise it's impossible to do stuff like:
```
StatusCheckBox {
  font.pixelSize: 15
}
```¨
2022-07-14 14:42:20 +02:00
Mikhail Rogachev e7b80a9ae2 feat(StatusScrollView): New scrollview component without twitches (#766) 2022-07-14 15:29:14 +03:00
Khushboo-dev-cpp 24a0e7472d fix(StatusAssetSelector): Fixes the issue of longer text overlapping with the arrow. Have also added a max width for the text after which it should elide (#772) 2022-07-14 11:03:39 +02:00
Pascal Precht 45d8990067 feat(StatusStackModal): introduce prevAction API
This adds a possible `prevAction` hook to `stackLayout.currentItem`
which is triggered (if it exists) when the stack modal's back button is
hit.
2022-07-14 10:12:54 +02:00
Pascal Precht c0d434bbdf fix(StatusBaseInput): ensure correct text color is set for disabled
state
2022-07-14 10:12:54 +02:00
Khushboo-dev-cpp c697467c68 fix: Minors fixes for issues found when using StatusFloatingButtons and implementing new SendModal (#748)
1. Fix the issue of floating buttons having incorrect color in Dark theme
2. Added balances param in StatusAssetSelector. ideally should be removed in another task as it is not the correct place for business logic
2022-07-14 00:05:42 +02:00
Khushboo-dev-cpp e2d42289f7 feat(StatusCard): Create a new reusbale card component (#731)
closes #582
2022-07-14 00:03:44 +02:00
Noelia e781645a58 feat(StatusItemSelector): Component improvements
-  Added `popupItem` property
- Replaced `GridLayout` to `Flow`.
- Added add item logic.
- Added operators logic.
- Added basic documentation.
- Added to sandbox.
2022-07-13 13:17:21 +02:00
Noelia c98f144fd8 feat(StatusIconTextButton): Created new control
It defines a button composed with an icon and plain text.
It has been documented and added to sandbox.
2022-07-13 13:17:21 +02:00
Noelia 016a0eac46 feat(StatusFloatValidator): Updated default bottom and top values 2022-07-13 13:17:21 +02:00
Noelia 29a61c7f5c feat(StatusSwitchTabButton): Added property pixelSize 2022-07-13 13:17:21 +02:00
Noelia a8b9020a4b feat(StatusPickerButton): Added configurable image in front of text 2022-07-13 13:17:21 +02:00
Noelia 8caf994220 chore(icons): Added arrow icon 2022-07-13 13:17:21 +02:00
Noelia 7709810ae2 feat(StatusDropdown): Basic dropdown template 2022-07-13 13:17:21 +02:00
Noelia d8e3557f8f feat(StatusBaseInput): Updated leftMargin depending if it is set from outside 2022-07-13 13:17:21 +02:00
Noelia 59143f7f34 feat(StatusInput): Added alias property to font and binding to left / right paddings 2022-07-13 13:17:21 +02:00
Noelia cb4094b128 feat(StatusItemSelector): First component iteration
- Layout, basic properties and signal.
- Default tag displayed.
- TODO: Selector logic.
2022-07-13 13:17:21 +02:00
Alexandra Betouni 99457ee77f fix(CreateChatView): fixed no contacts text alignment (#767)
As part of https://github.com/status-im/status-desktop/issues/6354
2022-07-13 11:59:53 +03:00
Alexandra Betouni c41318d5e8 fix(StatusAppChatView): Updated layout based on new designs (#765)
As part of https://github.com/status-im/status-desktop/issues/6352
2022-07-13 11:58:59 +03:00
dbcf4565f4 chore(StatusIcon): Include Object Name to Status Icon (#761)
* Include auto generated object names for all Icons.

This will help Squish tests easily identify Icons. Which is used in test case https://github.com/status-im/status-desktop/issues/6274

* Include auto generated object names for all Icons.

This will help Squish tests easily identify Icons. Which is used in test case https://github.com/status-im/status-desktop/issues/6274

* Include auto generated object names for all Icons.

This will help Squish tests easily identify Icons. Which is used in test case https://github.com/status-im/status-desktop/issues/6274

* refactor(isContact): rename isMutualContact to isContact

BREAKING CHANGE: isMutualContact is replaced by isContact anywhere it was used

* fix(StatusStackModal): init the next/finish buttons

call `updateRightButtons()` also on creation to correctly initialize the
Next and Finish buttons in derived classes, when one overrrides these

can be seen in the Backup Seed dialog where the Next button is not
enabled even though all 3 boxes are checked

* feat(StatusFontSettings): Add StatusFontSettings component to change StatusMenuItems font attributes (#749)

Required by #6090

* fix(StatusPinInput): `forceFocus` function exposed

* fix(StatusTagSelector): corrected font size in to label

Needed for https://github.com/status-im/status-desktop/issues/6349

* fix(StatusActivityCenterButton): fixed actvity icon position (#763)

Closes https://github.com/status-im/status-desktop/issues/6350

* Include auto generated object names for all Icons.

This will help Squish tests easily identify Icons. Which is used in test case https://github.com/status-im/status-desktop/issues/6274

* Include auto generated object names for all Icons.

This will help Squish tests easily identify Icons. Which is used in test case https://github.com/status-im/status-desktop/issues/6274

* Include auto generated object names for all Icons.

This will help Squish tests easily identify Icons. Which is used in test case https://github.com/status-im/status-desktop/issues/6274

Co-authored-by: Jonathan Rainville <rainville.jonathan@gmail.com>
Co-authored-by: Lukáš Tinkl <lukast@status.im>
Co-authored-by: Michał Iskierko <61889657+endulab@users.noreply.github.com>
Co-authored-by: Sale Djenic <aleksandardjenic@status.im>
Co-authored-by: Alexandra Betouni <31625338+alexandraB99@users.noreply.github.com>
2022-07-12 16:58:48 +01:00
Alexandra Betouni 9b1a033571 fix(StatusActivityCenterButton): fixed actvity icon position (#763)
Closes https://github.com/status-im/status-desktop/issues/6350
2022-07-12 18:00:47 +03:00
Alexandra Betouni 25600ec624 fix(StatusTagSelector): corrected font size in to label
Needed for https://github.com/status-im/status-desktop/issues/6349
2022-07-12 16:12:26 +02:00
Sale Djenic 2b4398830a fix(StatusPinInput): forceFocus function exposed 2022-07-12 12:52:30 +02:00
Michał Iskierko 05250a6eab feat(StatusFontSettings): Add StatusFontSettings component to change StatusMenuItems font attributes (#749)
Required by #6090
2022-07-12 11:05:12 +02:00
Lukáš Tinkl 9a2e28f2a7 fix(StatusStackModal): init the next/finish buttons
call `updateRightButtons()` also on creation to correctly initialize the
Next and Finish buttons in derived classes, when one overrrides these

can be seen in the Backup Seed dialog where the Next button is not
enabled even though all 3 boxes are checked
2022-07-12 10:21:14 +02:00
Jonathan Rainville a35d3dca8c refactor(isContact): rename isMutualContact to isContact
BREAKING CHANGE: isMutualContact is replaced by isContact anywhere it was used
2022-07-11 09:29:30 -04:00
Lukáš Tinkl 7363899a96 fix(StatusChatList): StatusChatListItem should follow parent's width
both StatusChatList and StatusChatListItem have the same hardcoded width
of 288, so if we want to make the former smaller, StatusChatListItem has
to obey that, otherwise it's cut on its right side in status-desktop

Status Desktop's new designs have a smaller width (272), this fix is
needed for status-im/status-desktop#6343
2022-07-08 10:11:10 +02:00
Kamil K c921cf7280 fix: handle animations by higher level nodes or states 2022-07-07 09:26:53 +02:00
Lukáš Tinkl e16804c4f0 fix(models): flag/currency icons are rendered blurred
exchange language/currency icons, PNG->SVG
2022-07-06 14:12:06 +02:00
Lukáš Tinkl f7c7f004e2 fix(StatusIcon): flag/currency icons are rendered blurred
- set the Image's sourceSize only if it's an SVG, otherwise it is
rendered blurry
- remove antialiasing/mipmap; it's not the correct fix, doesn't really
improve the visual quality for smallish items like icons and just causes
memory/GPU overhead
2022-07-06 14:12:06 +02:00
Patryk Osmaczko c4421d3552 feat(StatusDialog): introduce StatusDialog
closes: #725
2022-07-06 11:48:11 +02:00
Lukáš Tinkl cdf3059d3d fix(sandbox): enable the hover effects by default (#751)
Similar to what we did in status desktop under
d0a26a326e95a14a6a8a5634c0d30cd6dc648b54

- since Qt 5.xy, hover is not enabled by default for QQC2, so enable it
unconditionally as we are a desktop app anyway
- this fixes several hover effects being broken, mostly for builtin
components like MenuItem and some buttons (eg. the leftmost NavBar)
where we haven't enabled those with `hoverEnabled: true` explicitely
2022-07-04 17:09:00 +02:00
Lukáš Tinkl 5e590056ff fix(@sandbox): greatly speed up (re)build times (#746)
since most of the compilation time is spent on creating the QRC bundle
and the resulting binary is quite huge, advice the `rcc` compiler to add
support for "big resources"
(cf https://doc.qt.io/qt-6/resources.html#embedding-large-files)

Also pass the env $LDFLAGS to qmake (to be able to link e.g. with mold,
which again greatly reduces the time to link the binary)

this leads to 6-10x faster time when recompiling
(Linux, gcc 12.1.1, mold 1.3.0)

BEFORE:
Clean build:
real	0m57,256s
user	1m25,869s
sys	0m40,963s

Incremental build, one file touched:
real	0m54,323s
user	0m54,012s
sys	0m2,934s

AFTER:
Clean build:
real	0m7,276s
user	0m21,001s
sys	0m37,256s

Incremental build, one file touched:
real	0m5,569s
user	0m4,850s
sys	0m0,840s
2022-07-01 10:18:09 +02:00
Mikhail Rogachev 7b8cf2ffb5 feat(StatusStackModal): add subheader and remove explicit width (#747) 2022-06-30 20:35:20 +03:00
Igor Sirotin 6da838c81f fix(icons): Updated arrows icons (#735) 2022-06-30 09:24:04 +04:00
Mikhail Rogachev a2e9f813a5 Fix(StatusStackModal): fix height calculation (#745) 2022-06-29 14:04:17 -04:00
Iuri Matias 64d6beb4a0 bug(@status-q): only run animations when they are visible to avoid cpu issues (#744)
bug(@status-q): only run animations when they are visible to avoid cpu issues

remove prop that doesn't exist
2022-06-28 11:03:17 -04:00
Mikhail Rogachev 84c529d58d feat(StatusStackModal): Component to replace nested StausModals (#733) 2022-06-27 12:23:36 -04:00
Noelia fe355eebf8 fix(StatusChatToolBar): Updated activity center button size
Activity center button has now the same size than the other toolbar buttons.

Fixes https://github.com/status-im/status-desktop/issues/6216
2022-06-27 07:52:14 +02:00
Noelia b064f9ebd8 feat(StatusRoundButton): Added Tertiary type
- Transparent background but when hovered, like Primary type in idle state.

- Updated sandbox with the new type.
2022-06-27 07:50:22 +02:00
Sale Djenic 604bb7a74c fix(StatusToastMessage): clicked signal added 2022-06-23 19:52:23 +02:00
Jonathan Rainville 7d064d6c6e chore(StatusFlatRoundButon): fix warning related to hovered property 2022-06-23 11:44:06 -04:00
Noelia 1730fe756d fix(StatusCommunityCard): Added implicit width and height (#739)
Fixes https://github.com/status-im/status-desktop/issues/6206
2022-06-22 16:48:10 -04:00
Igor Sirotin 996717885d feat(icons): Added unpin icon (#738) 2022-06-22 16:47:51 +03:00
Igor Sirotin 34c223b581 feat(StatusListItem): Added loading and loadingFailed properties (#736) 2022-06-22 10:40:17 +03:00
Mikhail Rogachev 7b35be6691 fix(StatusCommunityTag): fix StatusCommunityTag and and ETH icon (#734) 2022-06-20 18:09:38 +03:00
Igor Sirotin 2186259c06 fix(contributing.md): Added Popup sizing guidelines (#728) 2022-06-17 14:37:52 +03:00
Mikhail Rogachev 69b5cb1988 feat(StatusCommunityTags): Add community tags component (#718) 2022-06-14 16:23:18 +03:00
Boris Melnik cb900fe494 feat(StatusQ.Controls): Introduce StatusActivityCenterButton (#705) 2022-06-14 13:01:08 +03:00
Igor Sirotin 1d618f72f7 fix(StatusBaseButton): Passed icon.rotation property to the icon component (#727) 2022-06-14 12:21:53 +03:00
Khushboo-dev-cpp d5df8b42a7 feat(StatusFloatingButtonsSelector): Implements the floating buttons selector widget (#681)
To be used in with StatusModal or independently
2022-06-14 11:07:08 +05:30
Igor Sirotin c0639d8b8e fix(StatusTabButton): Hide bottom dash in disabled state (#729) 2022-06-13 17:53:30 +03:00
239 changed files with 21175 additions and 14058 deletions
+3
View File
@@ -0,0 +1,3 @@
[submodule "vendor/SortFilterProxyModel"]
path = vendor/SortFilterProxyModel
url = https://github.com/status-im/SortFilterProxyModel.git
+18
View File
@@ -2,4 +2,22 @@ cmake_minimum_required(VERSION 3.19)
project(StatusQ)
if (APPLE)
set(MACOS_VERSION_MIN_FLAGS -mmacosx-version-min=10.14)
set(CMAKE_OSX_ARCHITECTURES "x86_64")
endif()
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# https://doc.qt.io/qtcreator/creator-qml-modules-with-plugins.html#importing-qml-modules
set(QML_IMPORT_PATH
${CMAKE_SOURCE_DIR}/src;${QML_IMPORT_PATH}
CACHE STRING "")
add_subdirectory(vendor/SortFilterProxyModel)
add_subdirectory(sandbox)
add_subdirectory(tests)
+5 -6
View File
@@ -36,7 +36,7 @@ To make viewing and testing components easy, we've added a sandbox application t
### Using Qt Creator
The easiest way to run the sandbox application is to simply open the provided `sandbox.pro` file using Qt Creator.
The easiest way to run the sandbox application is to simply open the provided `CMakeLists.txt` file using Qt Creator.
### Using command line interface
@@ -44,14 +44,13 @@ To run the sandbox from within a command line interface, run the following comma
```
$ git clone https://github.com/status-im/StatusQ
$ cd StatusQ/sandbox
$ ./scripts/build
$ cd StatusQ
$ git submodule update --init
$ ./sandbox/scripts/build
```
Once that is done, the sandbox can be started with the generated executable:
```
$ ./bin/sandbox
$ ./build/sandbox/Sandbox
```
More Documentation available on the [wiki](https://hackmd.io/@status-desktop/B1naRjxh_/%2FwFtiXvOiQqCdw2lk6gbOLA)
Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

+1
View File
@@ -20,6 +20,7 @@
\li \l{StatusChatToolBar}
\li \l{StatusContactRequestsIndicatorListItem}
\li \l{StatusDescriptionListItem}
\li \l{StatusItemSelector}
\li \l{StatusLetterIdenticon}
\li \l{StatusListItem}
\li \l{StatusListPicker}
+2
View File
@@ -15,6 +15,7 @@
\li \l{StatusChatInfoButton}
\li \l{StatusChatListCategoryItemButton}
\li \l{StatusColorSelector}
\li \l{StatusDropdown}
\li \l{StatusIconTabButton}
\li \l{StatusNavBarTabButton}
\li \l{StatusTabBarIconButton}
@@ -30,6 +31,7 @@
\li \l{StatusSlider}
\li \l{StatusSelect}
\li \l{StatusBaseInput}
\li \l{StatusIconTextButton}
\li \l{StatusIdenticonRing}
\li \l{StatusInput}
\li \l{StatusItemPicker}
+1
View File
@@ -12,6 +12,7 @@
\list
\li \l{StatusAppNavBarFilterModel}
\li \l{StatusBaseText}
\li \l{StatusFontSettings}
\li \l{StatusIcon}
\li \l{StatusIconBackgroundSettings}
\li \l{StatusIconSettings}
+38
View File
@@ -0,0 +1,38 @@
project(Sandbox)
find_package(
Qt5
COMPONENTS Core Quick QuickControls2
REQUIRED)
file(GLOB_RECURSE QML_FILES "../*.qml")
file(GLOB_RECURSE JS_FILES "../*.js")
file(GLOB_RECURSE HEADERS *.h)
if(APPLE)
file(GLOB_RECURSE SOURCES *.cpp *.mm)
else()
file(GLOB_RECURSE SOURCES *.cpp)
endif()
qt5_add_big_resources(QRC_FILES qml.qrc ../src/statusq.qrc ../src/assets.qrc)
add_executable(
${PROJECT_NAME}
${HEADERS}
${SOURCES}
${QRC_FILES}
${QML_FILES}
${JS_FILES})
target_compile_definitions(${PROJECT_NAME}
PRIVATE SRC_DIR="${CMAKE_CURRENT_LIST_DIR}")
target_link_libraries(
${PROJECT_NAME} PRIVATE Qt5::Core Qt5::Quick Qt5::QuickControls2
SortFilterProxyModel)
if (APPLE)
find_library(AppKit AppKit)
find_library(Foundation Foundation)
target_link_libraries(${PROJECT_NAME} PRIVATE ${AppKit} ${Foundation})
endif()
+5 -7
View File
@@ -63,7 +63,7 @@ Rectangle {
visible: titleStyle === "windows"
}
StatusAppLayout {
StatusMainLayout {
id: statusAppLayout
anchors.top: windowsTitle.visible ? windowsTitle.bottom : demoApp.top
anchors.left: demoApp.left
@@ -73,7 +73,7 @@ Rectangle {
height: demoApp.height - demoApp.border.width * 2
width: demoApp.width - demoApp.border.width * 2
appNavBar: StatusAppNavBar {
leftPanel: StatusAppNavBar {
id: navBar
@@ -174,16 +174,14 @@ Rectangle {
StatusMenuItem {
text: qsTr("Leave Community")
icon.name: "arrow-right"
icon.width: 14
iconRotation: 180
icon.name: "arrow-left"
type: StatusMenuItem.Type.Danger
}
}
}
}
appView: Loader {
rightPanel: Loader {
id: appView
anchors.fill: parent
sourceComponent: statusAppChatView
@@ -199,7 +197,7 @@ Rectangle {
id: statusAppCommunityView
StatusAppCommunityView {
communityDetailModalTitle: demoCommunityDetailModal.header.title
communityDetailModalImage: demoCommunityDetailModal.header.image.source
communityDetailModalImage: demoCommunityDetailModal.header.asset.name
onChatInfoButtonClicked: {
demoCommunityDetailModal.open();
}
+64
View File
@@ -17,6 +17,24 @@ Column {
horizontalItemAlignment: Grid.AlignHCenter
// Primary
StatusButton {
text: "Button"
type: StatusBaseButton.Type.Primary
}
StatusButton {
text: "Button"
enabled: false
type: StatusBaseButton.Type.Primary
}
StatusButton {
text: "Button"
loading: true
type: StatusBaseButton.Type.Primary
}
// Large
StatusButton {
text: "Button"
@@ -174,6 +192,25 @@ Column {
loading: true
}
// transparent
StatusRoundButton {
type: StatusRoundButton.Type.Tertiary
icon.name: "info"
}
StatusRoundButton {
type: StatusRoundButton.Type.Tertiary
icon.name: "info"
enabled: false
}
StatusRoundButton {
type: StatusRoundButton.Type.Tertiary
icon.name: "info"
loading: true
}
// Rounded blue
StatusFlatRoundButton {
@@ -319,4 +356,31 @@ Column {
}
}
// Button with emoji
StatusButton {
text: "Button with Emoji"
icon.emoji: "🖼️"
}
RowLayout {
spacing: 20
StatusIconTextButton {
Layout.alignment: Qt.AlignVCenter
spacing: 0
statusIcon: "next"
icon.width: 24
icon.height: 24
iconRotation: 180
text: "Previous page"
font.pixelSize: 15
onClicked: testText.visible = !testText.visible
}
StatusBaseText {
id: testText
Layout.alignment: Qt.AlignVCenter
text: "Click and hide!"
font.pixelSize: 15
}
}
}
+30 -13
View File
@@ -32,14 +32,14 @@ GridLayout {
}
StatusIconTabButton {
icon.source: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
icon.source: "qrc:/demoapp/data/profile-image-1.jpeg"
}
StatusIconTabButton {
icon.color: Theme.palette.miscColor9
// This icon source is flawed and demonstrates the fallback case
// when the image source can't be loaded
icon.source: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jp"
icon.source: "https://httpstat.us/404"
name: "Pascal"
}
@@ -86,7 +86,7 @@ GridLayout {
}
StatusNavBarTabButton {
icon.source: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
icon.source: "qrc:/demoapp/data/profile-image-1.jpeg"
tooltip.text: "Some Community"
}
@@ -113,18 +113,33 @@ GridLayout {
StatusSwitch {
}
StatusSwitch {
text: "Switch with text"
}
StatusRadioButton {
text: "i'm radio!"
text: "Radio button 1"
checked: true
}
StatusRadioButton {
text: "Radio button 2 (clicking on this text will uncheck the above)"
}
StatusRadioButton {
LayoutMirroring.enabled : true
text: "Radio button 3 (forced right-to-left)"
}
StatusCheckBox {}
StatusCheckBox { checkState: Qt.Checked}
StatusCheckBox { text: "Check me on left side"}
StatusCheckBox { text: "Check me on right side"; leftSide: false}
StatusChatInfoButton {
title: "Iuri Matias"
subTitle: "Contact"
icon.color: Theme.palette.miscColor7
image.source: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
asset.color: Theme.palette.miscColor7
asset.isImage: true
asset.name: "qrc:/demoapp/data/profile-image-1.jpeg"
type: StatusChatInfoButton.Type.OneToOneChat
muted: true
pinnedMessagesCount: 1
@@ -136,8 +151,9 @@ GridLayout {
StatusChatInfoButton {
title: "Iuri Matias elided"
subTitle: "Contact"
icon.color: Theme.palette.miscColor7
image.source: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
asset.color: Theme.palette.miscColor7
asset.isImage: true
asset.name: "qrc:/demoapp/data/profile-image-1.jpeg"
type: StatusChatInfoButton.Type.OneToOneChat
muted: true
pinnedMessagesCount: 1
@@ -151,8 +167,9 @@ GridLayout {
StatusChatInfoButton {
title: "Iuri Matias big not elided"
subTitle: "Contact"
icon.color: Theme.palette.miscColor7
image.source: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
asset.color: Theme.palette.miscColor7
asset.isImage: true
asset.name: "qrc:/demoapp/data/profile-image-1.jpeg"
type: StatusChatInfoButton.Type.OneToOneChat
muted: true
pinnedMessagesCount: 1
@@ -164,21 +181,21 @@ GridLayout {
title: "group"
subTitle: "Group Chat"
pinnedMessagesCount: 1
icon.color: Theme.palette.miscColor7
asset.color: Theme.palette.miscColor7
type: StatusChatInfoButton.Type.GroupChat
}
StatusChatInfoButton {
title: "public-chat"
subTitle: "Public Chat"
icon.color: Theme.palette.miscColor7
asset.color: Theme.palette.miscColor7
type: StatusChatInfoButton.Type.PublicChat
}
StatusChatInfoButton {
title: "community-channel"
subTitle: "Community Chat"
icon.color: Theme.palette.miscColor7
asset.color: Theme.palette.miscColor7
type: StatusChatInfoButton.Type.CommunityChat
}
+50 -78
View File
@@ -12,93 +12,73 @@ import StatusQ.Popups 0.1
Column {
spacing: 10
StatusChatToolBar {
toolbarComponent: chatInfoButton1
StatusToolBar {
width: 518
Component {
id: chatInfoButton1
StatusChatInfoButton {
width: Math.min(implicitWidth, parent.width)
title: "Some contact"
subTitle: "Contact"
icon.color: Theme.palette.miscColor7
type: StatusChatInfoButton.Type.OneToOneChat
}
headerContent: StatusChatInfoButton {
width: Math.min(implicitWidth, parent.width)
title: "Some contact"
subTitle: "Contact"
asset.color: Theme.palette.miscColor7
type: StatusChatInfoButton.Type.OneToOneChat
}
}
StatusChatToolBar {
toolbarComponent: chatInfoButton2
StatusToolBar {
width: 518
Component {
id: chatInfoButton2
StatusChatInfoButton {
width: Math.min(implicitWidth, parent.width)
title: "Some contact"
subTitle: "Contact"
icon.color: Theme.palette.miscColor7
type: StatusChatInfoButton.Type.PublicChat
pinnedMessagesCount: 1
muted: true
}
headerContent: StatusChatInfoButton {
width: Math.min(implicitWidth, parent.width)
title: "Some contact"
subTitle: "Contact"
asset.color: Theme.palette.miscColor7
type: StatusChatInfoButton.Type.PublicChat
pinnedMessagesCount: 1
muted: true
}
}
StatusChatToolBar {
StatusToolBar {
notificationCount: 1
toolbarComponent: chatInfoButton3
width: 518
Component {
id: chatInfoButton3
StatusChatInfoButton {
width: Math.min(implicitWidth, parent.width)
title: "Some contact"
subTitle: "Contact"
icon.color: Theme.palette.miscColor7
type: StatusChatInfoButton.Type.OneToOneChat
pinnedMessagesCount: 1
}
headerContent: StatusChatInfoButton {
width: Math.min(implicitWidth, parent.width)
title: "Some contact"
subTitle: "Contact"
asset.color: Theme.palette.miscColor7
type: StatusChatInfoButton.Type.OneToOneChat
pinnedMessagesCount: 1
}
}
StatusChatToolBar {
StatusToolBar {
notificationCount: 1
toolbarComponent: tagSelector
width: 518
Component {
id: tagSelector
StatusTagSelector {
namesModel: ListModel {
ListElement {
publicId: "0x0"
name: "Maria"
icon: ""
isIdenticon: false
onlineStatus: 3
isReadonly: true
tagIcon: "crown"
}
ListElement {
publicId: "0x1"
name: "James"
icon: ""
isIdenticon: false
onlineStatus: 1
isReadonly: false
tagIcon: ""
}
StatusTagSelector {
namesModel: ListModel {
ListElement {
publicId: "0x0"
name: "Maria"
icon: ""
isIdenticon: false
onlineStatus: 3
isReadonly: true
tagIcon: "crown"
}
ListElement {
publicId: "0x1"
name: "James"
icon: ""
isIdenticon: false
onlineStatus: 1
isReadonly: false
tagIcon: ""
}
toLabelText: qsTr("To: ")
warningText: qsTr("USER LIMIT REACHED")
}
toLabelText: qsTr("To: ")
warningText: qsTr("USER LIMIT REACHED")
}
}
@@ -223,9 +203,7 @@ Column {
StatusMenuItem {
text: qsTr("Leave Community")
icon.name: "arrow-right"
icon.width: 14
iconRotation: 180
icon.name: "arrow-left"
type: StatusMenuItem.Type.Danger
}
}
@@ -308,9 +286,7 @@ Column {
StatusMenuItem {
text: qsTr("Leave Community")
icon.name: "arrow-right"
icon.width: 14
iconRotation: 180
icon.name: "arrow-left"
type: StatusMenuItem.Type.Danger
}
}
@@ -398,9 +374,7 @@ Column {
StatusMenuItem {
text: qsTr("Leave Community")
icon.name: "arrow-right"
icon.width: 14
iconRotation: 180
icon.name: "arrow-left"
type: StatusMenuItem.Type.Danger
}
}
@@ -493,9 +467,7 @@ Column {
StatusMenuItem {
text: qsTr("Leave Community")
icon.name: "arrow-right"
icon.width: 14
iconRotation: 180
icon.name: "arrow-left"
type: StatusMenuItem.Type.Danger
}
}
+185 -54
View File
@@ -1,4 +1,6 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQml.Models 2.14
import QtQuick.Layouts 1.14
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
@@ -6,10 +8,8 @@ import StatusQ.Controls 0.1
import StatusQ.Components 0.1
import StatusQ.Core.Utils 0.1
GridLayout {
columns: 1
columnSpacing: 5
rowSpacing: 5
ColumnLayout {
spacing: 5
StatusNavigationListItem {
title: "Menu Item"
@@ -17,18 +17,18 @@ GridLayout {
StatusNavigationListItem {
title: "Menu Item"
icon.name: "info"
asset.name: "info"
}
StatusNavigationListItem {
title: "Menu Item"
icon.name: "info"
asset.name: "info"
badge.value: 1
}
StatusNavigationListItem {
title: "Menu Item (selected) with very long text"
selected: true
icon.name: "info"
asset.name: "info"
badge.value: 1
}
@@ -55,6 +55,59 @@ GridLayout {
opened: true
}
StatusChatListCategoryItem {
id: categoryItemInteractive
title: "Chat category interactive"
showActionButtons: true
onAddButtonClicked: testEventsList.eventTriggered("Add button clicked")
onMenuButtonClicked: testEventsList.eventTriggered("Menu button clicked")
onToggleButtonClicked: {
opened = !opened
testEventsList.eventTriggered("Toggle button clicked")
}
onTitleClicked: {
testEventsList.eventTriggered("Title clicked")
}
onClicked: {
opened = !opened
testEventsList.eventTriggered("Item clicked", itemId)
}
}
ListView {
id: testEventsList
Layout.fillWidth: true
Layout.preferredHeight: categoryItemInteractive.opened ? 20 * count : 0
clip: true
function eventTriggered(message) {
let obj = eventDelegateComponent.createObject()
obj.text = message
model.insert(0, obj)
}
Component {
id: eventDelegateComponent
ItemDelegate {
implicitHeight: 20
property int index: ObjectModel.index
Timer {
interval: 5000; running: true
onTriggered: testObjectModel.remove(index)
}
}
}
model: ObjectModel {
id: testObjectModel
}
}
StatusChatListItem {
name: "group-chat"
type: StatusChatListItem.Type.GroupChat
@@ -68,18 +121,20 @@ GridLayout {
StatusChatListItem {
name: "community-channel-emoji"
type: StatusChatListItem.Type.CommunityChat
icon.emoji: "😁"
asset.emoji: "😁"
}
StatusChatListItem {
name: "community-channel-with-image"
image.source: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
asset.isImage: true
asset.name: "qrc:/demoapp/data/profile-image-1.jpeg"
type: StatusChatListItem.Type.CommunityChat
}
StatusChatListItem {
name: "Weird Crazy Otter"
image.source: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
asset.isImage: true
asset.name: "qrc:/demoapp/data/profile-image-1.jpeg"
type: StatusChatListItem.Type.OneToOneChat
}
@@ -164,7 +219,7 @@ GridLayout {
title: "Title"
subTitle: "Super long description that causes a multiline paragraph and makes the size of the component grow. Let's see how it behaves."
tertiaryTitle: "Tertiary title"
icon.name: "info"
asset.name: "info"
statusListItemTitle.font.pixelSize: 17
statusListItemTitle.font.weight: Font.Bold
@@ -173,27 +228,29 @@ GridLayout {
StatusListItem {
title: "Title"
subTitle: "Subtitle"
icon.name: "info"
asset.name: "info"
}
StatusListItem {
title: "Title"
subTitle: "Subtitle"
image.source: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
asset.isImage: true
asset.name: "qrc:/demoapp/data/profile-image-1.jpeg"
}
StatusListItem {
title: "Title"
subTitle: "Subtitle"
image.source: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0Bh
CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
image.isIdenticon: true
asset.isImage: true
asset.name: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0BhCExPynn1gWf9bx498P7/
nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
asset.imgIsIdenticon: true
}
StatusListItem {
title: "Title"
subTitle: "Subtitle"
icon.name: "info"
asset.name: "info"
components: [StatusButton {
text: "Button"
size: StatusBaseButton.Size.Small
@@ -203,35 +260,35 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
StatusListItem {
title: "Title"
subTitle: "Subtitle"
icon.name: "info"
asset.name: "info"
components: [StatusSwitch {}]
}
StatusListItem {
title: "Title"
subTitle: "Subtitle"
icon.name: "info"
asset.name: "info"
components: [StatusRadioButton {}]
}
StatusListItem {
title: "Title"
subTitle: "Subtitle"
icon.name: "info"
asset.name: "info"
components: [StatusCheckBox {}]
}
StatusListItem {
title: "Title"
subTitle: "Subtitle"
icon.name: "info"
asset.name: "info"
label: "Text"
}
StatusListItem {
title: "Title"
subTitle: "Subtitle"
icon.name: "info"
asset.name: "info"
label: "Text"
components: [
StatusButton {
@@ -244,7 +301,7 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
StatusListItem {
title: "Title"
subTitle: "Subtitle"
icon.name: "info"
asset.name: "info"
label: "Text"
components: [StatusSwitch {}]
}
@@ -252,7 +309,7 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
StatusListItem {
title: "Title"
subTitle: "Subtitle"
icon.name: "info"
asset.name: "info"
label: "Text"
components: [
StatusRadioButton {}
@@ -262,7 +319,7 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
StatusListItem {
title: "Title"
subTitle: "Subtitle"
icon.name: "info"
asset.name: "info"
label: "Text"
components: [StatusCheckBox {}]
}
@@ -270,7 +327,7 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
StatusListItem {
title: "Title"
subTitle: "Subtitle"
icon.name: "info"
asset.name: "info"
label: "Text"
components: [
StatusBadge {
@@ -287,14 +344,14 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
StatusListItem {
title: "Title"
icon.name: "info"
asset.name: "info"
type: StatusListItem.Type.Secondary
}
StatusListItem {
title: "Title"
icon.isLetterIdenticon: true
icon.color: "orange"
asset.isLetterIdenticon: true
asset.color: "orange"
}
StatusListItem {
@@ -304,17 +361,19 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
StatusListItem {
title: "Title"
icon.name: "delete"
asset.name: "delete"
type: StatusListItem.Type.Danger
}
StatusListItem {
title: "List Item with Badge"
subTitle: "Subtitle"
image.source: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0Bh
CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
image.isIdenticon: true
badge.image.source: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
asset.isImage: true
asset.name: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0BhCExPynn1gWf9bx498P7/
nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
asset.imgIsIdenticon: true
badge.asset.isImage: true
badge.asset.name: "qrc:/demoapp/data/profile-image-1.jpeg"
badge.primaryText: "CryptoKitties"
badge.secondaryText: "#test"
}
@@ -322,36 +381,57 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
StatusListItem {
title: "List Item with Badge 2"
subTitle: "Subtitle"
icon.isLetterIdenticon: true
asset.isLetterIdenticon: true
badge.primaryText: "CryptoKitties"
badge.secondaryText: "#test"
badge.icon.color: "orange"
badge.icon.isLetterIdenticon: true
badge.asset.color: "orange"
badge.asset.isLetterIdenticon: true
}
StatusListItem {
title: "List Item with Tags"
icon.isLetterIdenticon: true
asset.isLetterIdenticon: true
bottomModel: 3
bottomDelegate: StatusListItemTag {
title: "tag"
icon.isLetterIdenticon: true
asset.isLetterIdenticon: true
}
}
StatusListItem {
title: "List Item with Inline Tags"
icon.isLetterIdenticon: true
tagsModel : 2
asset.isLetterIdenticon: true
tagsModel: ListModel{
ListElement {
name: "helloworld.eth"
emoji: "😁"
}
ListElement {
name: "account1"
emoji: "😁"
}
ListElement {
name: "account2"
emoji: "😁"
}
ListElement {
name: "account3"
emoji: "😁"
}
ListElement {
name: "account4"
emoji: "😁"
}
}
tagsDelegate: StatusListItemTag {
color: "blue"
height: 24
radius: 6
closeButtonVisible: false
icon.emoji: "😁"
icon.emojiSize: Emoji.size.verySmall
icon.isLetterIdenticon: true
title: "helloworld.eth"
asset.emoji: model.emoji
asset.emojiSize: Emoji.size.verySmall
asset.isLetterIdenticon: true
title: model.name
titleText.font.pixelSize: 12
titleText.color: Theme.palette.indirectColor1
}
@@ -360,10 +440,10 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
StatusListItem {
title: "List Item with Emoji"
subTitle: "Emoji"
icon.emoji: "😁"
icon.color: "yellow"
icon.letterSize: 14
icon.isLetterIdenticon: true
asset.emoji: "😁"
asset.color: "yellow"
asset.letterSize: 14
asset.isLetterIdenticon: true
}
StatusDescriptionListItem {
@@ -382,7 +462,7 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
title: "Title"
subTitle: "Subtitle"
tooltip.text: "Tooltip"
icon.name: "info"
asset.name: "info"
iconButton.onClicked: tooltip.visible = !tooltip.visible
}
@@ -397,9 +477,10 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
pubKey: "0x043a7ed0e8752236a4688563652fd0296453cef00a5dcddbe252dc74f72cc1caa97a2b65e4a1a52d9c30a84c9966beaaaf6b333d659cbdd2e486b443ed1012cf04"
isVerified: true
isContact: true
image.source: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0BhCExPynn1gWf9bx498P7/
asset.isImage: true
asset.name: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0BhCExPynn1gWf9bx498P7/
nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
image.isIdenticon: true
asset.imgIsIdenticon: true
status: 1 // FIXME: use enum
ringSettings.ringSpecModel:
ListModel {
@@ -417,16 +498,27 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
StatusMemberListItem {
nickName: "carmen.eth"
isUntrustworthy: true
asset.isLetterIdenticon: true
}
StatusMemberListItem {
nickName: "very-long-annoying-nickname.eth"
isUntrustworthy: true
asset.isLetterIdenticon: true
}
StatusMemberListItem {
nickName: "untrusted-admin.eth"
asset.isLetterIdenticon: true
isUntrustworthy: true
isAdmin: true
isContact: true
}
StatusMemberListItem {
nickName: "This girl I know from work"
userName: "annabelle"
asset.isLetterIdenticon: true
status: 1 // FIXME: use enum
}
@@ -435,14 +527,53 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
userName: "annabelle"
pubKey: "0x043a7ed0e8752236a4688563652fd0296453cef00a5dcddbe252dc74f72cc1caa97a2b65e4a1a52d9c30a84c9966beaaaf6b333d659cbdd2e486b443ed1012cf04"
isContact: true
image.source: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0BhCExPynn1gWf9bx498P7/
asset.isImage: true
asset.name: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0BhCExPynn1gWf9bx498P7/
nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
image.isIdenticon: true
asset.imgIsIdenticon: true
}
StatusMemberListItem {
nickName: "admin.guy"
userName: "adguy"
isAdmin: true
asset.isLetterIdenticon: true
isUntrustworthy: true
Component.onCompleted: {
print(asset.name, asset.isImage, asset.isLetterIdenticon)
}
}
StatusBaseText {
Layout.fillWidth: true
Layout.topMargin: 16
text: "Loading features:"
font.pixelSize: 17
}
StatusListItem {
title: "Nokia 3310"
subTitle: "Incoming device"
label: "loading: true"
asset.width: 40
asset.height: 40
asset.emoji: "😁"
asset.color: "hotpink"
asset.letterSize: 14
asset.isLetterIdenticon: true
loading: true
}
StatusListItem {
title: "Nokia 3310"
subTitle: "Device"
label: "loadingFailed: true"
asset.width: 40
asset.height: 40
asset.emoji: "😁"
asset.color: "hotpink"
asset.letterSize: 14
asset.isLetterIdenticon: true
loadingFailed: true
}
}
+6 -3
View File
@@ -22,7 +22,7 @@ ColumnLayout {
}
StatusRoundedImage {
image.source: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
image.source: "qrc:/demoapp/data/profile-image-1.jpeg"
}
StatusBadge {}
@@ -40,7 +40,7 @@ ColumnLayout {
}
StatusRoundIcon {
icon.name: "info"
asset.name: "info"
}
}
@@ -57,5 +57,8 @@ ColumnLayout {
}
}
}
}
StatusDatePicker {
label: "Select date"
}
}
+80 -29
View File
@@ -4,6 +4,8 @@ import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Popups 0.1
import StatusQ.Components 0.1
import StatusQ.Core.Utils 0.1
Column {
spacing: 20
@@ -83,6 +85,12 @@ Column {
onClicked: advancedHeaderFooterModal.open()
}
StatusButton {
text: "Modal with Floating header Buttons"
onClicked: floatingHeaderModal.open()
}
StatusModal {
id: simpleModal
anchors.centerIn: parent
@@ -101,7 +109,8 @@ Column {
anchors.centerIn: parent
header.title: "Some Title"
header.subTitle: "Subtitle"
header.image.source: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
header.asset.isImage: true
header.asset.name: "qrc:/demoapp/data/profile-image-1.jpeg"
}
StatusModal {
@@ -109,12 +118,10 @@ Column {
anchors.centerIn: parent
header.title: "Some Title"
header.subTitle: "Subtitle"
header.image.source: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
header.asset.isImage: true
header.asset.name: "qrc:/demoapp/data/profile-image-1.jpeg"
leftButtons: [
StatusRoundButton {
icon.name: "arrow-right"
rotation: 180
}
StatusBackButton { }
]
rightButtons: [
StatusButton {
@@ -131,7 +138,8 @@ Column {
anchors.centerIn: parent
header.title: "Some Title"
header.subTitle: "Subtitle"
header.image.source: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
header.asset.isImage: true
header.asset.name: "qrc:/demoapp/data/profile-image-1.jpeg"
headerActionButton: StatusFlatRoundButton {
type: StatusFlatRoundButton.Type.Secondary
@@ -144,10 +152,7 @@ Column {
}
leftButtons: [
StatusRoundButton {
icon.name: "arrow-right"
rotation: 180
}
StatusBackButton { }
]
rightButtons: [
StatusButton {
@@ -162,7 +167,8 @@ Column {
StatusModal {
id: modalExample
anchors.centerIn: parent
header.image.source: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
header.asset.isImage: true
header.asset.name: "qrc:/demoapp/data/profile-image-1.jpeg"
header.title: "Header"
header.subTitle: "SubTitle"
rightButtons: [
@@ -175,10 +181,7 @@ Column {
]
leftButtons: [
StatusRoundButton {
icon.name: "arrow-right"
rotation: 180
}
StatusBackButton { }
]
contentItem: StatusBaseText {
@@ -228,8 +231,8 @@ Column {
anchors.centerIn: parent
header.title: "Header"
header.subTitle: "SubTitle"
header.icon.isLetterIdenticon: true
header.icon.background.color: "red"
header.asset.isLetterIdenticon: true
header.asset.bgColor: "red"
contentItem: StatusBaseText {
anchors.centerIn: parent
@@ -253,9 +256,9 @@ Column {
anchors.centerIn: parent
header.title: "Header"
header.subTitle: "SubTitle"
header.image.source: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0Bh
CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
header.image.isIdenticon: true
header.asset.name: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0BhCExPynn1gWf9bx498P7/
nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
header.asset.imgIsIdenticon: true
contentItem: StatusBaseText {
anchors.centerIn: parent
@@ -280,9 +283,9 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
header.title: "Header"
header.subTitle: "SubTitle"
header.headerImageEditable: true
header.image.source: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0Bh
CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
header.image.isIdenticon: true
header.asset.name: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0BhCExPynn1gWf9bx498P7/
nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
header.asset.imgIsIdenticon: true
contentItem: StatusBaseText {
anchors.centerIn: parent
@@ -307,9 +310,9 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
header.title: "Some super long text here that exceeds the available space"
header.subTitle: "Some super long text here that exceeds the available space"
header.subTitleElide: Text.ElideMiddle
header.image.source: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0Bh
CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
header.image.isIdenticon: true
header.asset.name: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0BhCExPynn1gWf9bx498P7/
nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
header.asset.imgIsIdenticon: true
contentItem: StatusBaseText {
anchors.centerIn: parent
@@ -341,7 +344,7 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
sourceComponent: popupMenu.delegate
onLoaded: {
item.action.text = model.name
item.action.iconSettings.name = model.iconName
item.action.assetSettings.name = model.iconName
}
}
}
@@ -394,10 +397,58 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
}
}
StatusModal {
id: floatingHeaderModal
anchors.centerIn: parent
height: 200
showHeader: false
showFooter: false
showAdvancedHeader: true
hasFloatingButtons: true
advancedHeaderComponent: StatusFloatingButtonsSelector {
id: floatingHeader
model: dummyAccountsModel
delegate: Rectangle {
width: button.width
height: button.height
radius: 8
visible: visibleIndices.includes(index)
color: Theme.palette.statusAppLayout.backgroundColor
StatusButton {
id: button
topPadding: 8
bottomPadding: 0
implicitHeight: 32
defaultLeftPadding: 4
text: name
icon.emoji: !!emoji ? emoji: ""
icon.emojiSize: Emoji.size.middle
icon.name: !emoji ? "filled-account": ""
normalColor: "transparent"
highlighted: index === floatingHeader.currentIndex
onClicked: {
floatingHeader.currentIndex = index
}
}
}
popupMenuDelegate: StatusListItem {
implicitWidth: 272
title: name
onClicked: floatingHeader.itemSelected(index)
visible: !visibleIndices.includes(index)
}
}
}
ListModel {
id: dummyAccountsModel
ListElement{name: "Account 1"; iconName: "filled-account"}
ListElement{name: "Account 1"; iconName: "filled-account"; emoji: "🥑"}
ListElement{name: "Account 2"; iconName: "filled-account"}
ListElement{name: "Account 3"; iconName: "filled-account"}
ListElement{name: "Account 4"; iconName: "filled-account"}
ListElement{name: "Account 5"; iconName: "filled-account"}
ListElement{name: "Account 6"; iconName: "filled-account"}
ListElement{name: "Account 7"; iconName: "filled-account"}
}
StatusSpellcheckingMenuItems {
+49 -22
View File
@@ -14,9 +14,10 @@ ListView {
anchors.fill: parent
anchors.margins: 15
clip: true
delegate: StatusMessage {
id: delegate
width: parent.width
width: ListView.view.width
audioMessageInfoText: "Audio Message"
cancelButtonText: "Cancel"
@@ -26,44 +27,70 @@ ListView {
resendText: "Resend"
pinnedMsgInfoText: "Pinned by"
timestamp: model.timestamp
isAReply: model.isReply
hasMention: model.hasMention
isPinned: model.isPinned
pinnedBy: model.pinnedBy
hasExpired: model.hasExpired
reactionsModel: model.reactions || []
messageDetails: StatusMessageDetails {
contentType: model.contentType
messageContent: model.messageContent
amISender: model.amIsender
displayName: model.userName
secondaryName: model.localName !== "" && model.ensName.startsWith("@") ? model.ensName: ""
chatID: model.chatKey
profileImage: StatusImageSettings {
sender.id: model.senderId
sender.userName: model.userName
sender.localName: model.localName
sender.ensName: model.ensName
sender.isContact: model.isContact
sender.trustIndicator: model.trustIndicator
sender.profileImage: StatusProfileImageSettings {
width: 40
height: 40
source: model.profileImage
isIdenticon: model.isIdenticon
pubkey: model.senderId
name: model.profileImage || ""
colorId: 1
colorHash: ListModel {
ListElement { colorId: 13; segmentLength: 5 }
ListElement { colorId: 31; segmentLength: 5 }
ListElement { colorId: 10; segmentLength: 1 }
ListElement { colorId: 2; segmentLength: 5 }
ListElement { colorId: 26; segmentLength: 2 }
ListElement { colorId: 19; segmentLength: 4 }
ListElement { colorId: 28; segmentLength: 3 }
}
}
messageText: model.message
hasMention: model.hasMention
isMutualContact: model.isMutualContact
trustIndicator: model.trustIndicator
isPinned: model.isPinned
pinnedBy: model.pinnedBy
hasExpired: model.hasExpired
}
timestamp.text: "10:00 am"
timestamp.tooltip.text: "10:01 am"
// reply related data
isAReply: model.isReply
replyDetails: StatusMessageDetails {
amISender: model.isReply ? model.replyAmISender : ""
displayName: model.isReply ? model.replySenderName: ""
profileImage: StatusImageSettings {
amISender: model.isReply && model.replyAmISender
sender.id: model.replySenderId || ""
sender.userName: model.isReply ? model.replySenderName: ""
sender.ensName: model.isReply ? model.replySenderEnsName : ""
sender.profileImage: StatusProfileImageSettings {
width: 20
height: 20
source: model.isReply ? model.replyProfileImage: ""
isIdenticon: model.isReply ? model.replyIsIdenticon: ""
name: model.isReply ? model.replyProfileImage: ""
pubkey: model.replySenderId
colorId: 1
colorHash: ListModel {
ListElement { colorId: 13; segmentLength: 5 }
ListElement { colorId: 31; segmentLength: 5 }
ListElement { colorId: 10; segmentLength: 1 }
ListElement { colorId: 2; segmentLength: 5 }
ListElement { colorId: 26; segmentLength: 2 }
ListElement { colorId: 19; segmentLength: 4 }
ListElement { colorId: 28; segmentLength: 3 }
}
}
messageText: model.isReply ? model.replyMessageText: ""
contentType: model.replyContentType
messageContent: model.replyMessageContent
}
quickActions: [
StatusFlatRoundButton {
id: emojiBtn
+29 -7
View File
@@ -20,6 +20,7 @@ Page {
height: tagSelector.height
anchors.right: parent.right
anchors.rightMargin: 8
spacing: 16
StatusTagSelector {
id: tagSelector
@@ -69,31 +70,52 @@ Page {
Component.onCompleted: {
textEdit.forceActiveFocus();
sortModel(root.contactsModel);
//add admin tag
namesModel.append({
"pubKey": "0x043a7ed78362567894688563652fd0296453cef00a5dcddbe252dc74f72cc1caa97a2b65e4a1a52d9c30a84c9966beaaaf6b333d659cbdd2e486b443ed1012cf04",
"name": "carmen.eth",
"tagIcon": "crown",
"isReadonly": true});
}
}
StatusButton {
implicitWidth: 106
implicitHeight: 44
Layout.alignment: Qt.AlignTop
enabled: (tagSelector.namesModel.count > 0)
enabled: (tagSelector.namesModel.count > 1)
text: "Confirm"
}
Item {
implicitHeight: 32
implicitWidth: 32
Layout.alignment: Qt.AlignTop
StatusActivityCenterButton {
id: notificationButton
anchors.right: parent.right
unreadNotificationsCount: 3
}
}
}
contentItem: Item {
anchors.fill: parent
anchors.topMargin: 68
StatusBaseText {
visible: (contactsModel.count === 0)
anchors.centerIn: parent
width: Math.min(553, parent.width - 32)
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: -(headerRow.height/2)
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
visible: contactsModel.count === 0
wrapMode: Text.WordWrap
font.pixelSize: 15
color: Theme.palette.baseColor1
text: qsTr("You can only send direct messages to your Contacts. \n\n
Send a contact request to the person you would like to chat with, you will be\n able to
chat with them once they have accepted your contact request.")
text: qsTr("You can only send direct messages to your Contacts.\n
Send a contact request to the person you would like to chat with, you will be able to chat with them once they have accepted your contact request.")
Component.onCompleted: {
if (visible) {
tagSelector.enabled = false;
+8 -8
View File
@@ -13,7 +13,8 @@ StatusModal {
header.title: "Cryptokitties"
header.subTitle: "Public Community"
header.image.source: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
header.asset.isImage: true
header.asset.name: "qrc:/demoapp/data/profile-image-1.jpeg"
contentItem: Column {
width: root.width
@@ -43,7 +44,7 @@ StatusModal {
title: "Share community"
subTitle: "https://join.status.im/u/0x04...45f19"
tooltip.text: "Copy to clipboard"
icon.name: "copy"
asset.name: "copy"
iconButton.onClicked: tooltip.visible = !tooltip.visible
width: parent.width
}
@@ -57,7 +58,7 @@ StatusModal {
anchors.horizontalCenter: parent.horizontalCenter
statusListItemTitle.font.pixelSize: 17
title: "Members"
icon.name: "group-chat"
asset.name: "group-chat"
label: "184"
components: [
StatusIcon {
@@ -72,7 +73,7 @@ StatusModal {
anchors.horizontalCenter: parent.horizontalCenter
statusListItemTitle.font.pixelSize: 17
title: "Notifications"
icon.name: "notification"
asset.name: "notification"
components: [
StatusSwitch {}
]
@@ -87,7 +88,7 @@ StatusModal {
anchors.horizontalCenter: parent.horizontalCenter
statusListItemTitle.font.pixelSize: 17
title: "Edit community"
icon.name: "edit"
asset.name: "edit"
type: StatusListItem.Type.Secondary
}
@@ -95,7 +96,7 @@ StatusModal {
anchors.horizontalCenter: parent.horizontalCenter
statusListItemTitle.font.pixelSize: 17
title: "Transfer ownership"
icon.name: "exchange"
asset.name: "exchange"
type: StatusListItem.Type.Secondary
}
@@ -103,8 +104,7 @@ StatusModal {
anchors.horizontalCenter: parent.horizontalCenter
statusListItemTitle.font.pixelSize: 17
title: "Leave community"
icon.name: "arrow-right"
icon.rotation: 180
asset.name: "arrow-left"
type: StatusListItem.Type.Secondary
}
}
+155 -80
View File
@@ -10,66 +10,195 @@ import StatusQ.Core.Theme 0.1
import "data" 1.0
StatusAppThreePanelLayout {
StatusSectionLayout {
id: root
property bool createChat: false
leftPanel: Item {
anchors.fill: parent
notificationCount: 1
onNotificationButtonClicked: { notificationCount = 0; }
showHeader: !root.createChat
StatusNavigationPanelHeadline {
id: headline
anchors.top: parent.top
anchors.topMargin: 16
anchors.horizontalCenter: parent.horizontalCenter
text: "Chat"
headerContent: RowLayout {
id: chatHeader
signal chatInfoButtonClicked()
signal menuButtonClicked()
signal membersButtonClicked()
signal searchButtonClicked()
StatusChatInfoButton {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.alignment: Qt.AlignLeft
Layout.leftMargin: padding
title: "Amazing Funny Squirrel"
subTitle: "Contact"
asset.color: Theme.palette.miscColor7
type: StatusChatInfoButton.Type.OneToOneChat
pinnedMessagesCount: 1
}
RowLayout {
id: searchInputWrapper
width: 288
height: searchInput.height
anchors.top: headline.bottom
anchors.topMargin: 16
anchors.horizontalCenter: parent.horizontalCenter
id: actionButtons
Layout.alignment: Qt.AlignRight
Layout.rightMargin: padding
spacing: 8
StatusBaseInput {
id: searchInput
Layout.fillWidth: true
StatusFlatRoundButton {
id: menuButton
objectName: "chatToolbarMoreOptionsButton"
width: 32
height: 32
icon.name: "more"
type: StatusFlatRoundButton.Type.Secondary
// initializing the tooltip
tooltip.visible: !!tooltip.text && menuButton.hovered && !contextMenu.open
tooltip.text: qsTr("More")
tooltip.orientation: StatusToolTip.Orientation.Bottom
tooltip.y: parent.height + 12
property bool showMoreMenu: false
onClicked: {
menuButton.highlighted = true
let originalOpenHandler = contextMenu.openHandler
let originalCloseHandler = contextMenu.closeHandler
contextMenu.openHandler = function () {
if (!!originalOpenHandler) {
originalOpenHandler()
}
}
contextMenu.closeHandler = function () {
menuButton.highlighted = false
if (!!originalCloseHandler) {
originalCloseHandler()
}
}
contextMenu.openHandler = originalOpenHandler
contextMenu.popup(-contextMenu.width + menuButton.width, menuButton.height + 4)
}
StatusPopupMenu {
id: contextMenu
StatusMenuItem {
text: "Mute Chat"
icon.name: "notification"
}
StatusMenuItem {
text: "Mark as Read"
icon.name: "checkmark-circle"
}
StatusMenuItem {
text: "Clear History"
icon.name: "close-circle"
}
StatusMenuSeparator {}
StatusMenuItem {
text: "Leave Chat"
icon.name: "arrow-left"
type: StatusMenuItem.Type.Danger
}
}
}
Rectangle {
width: 1
height: 24
color: Theme.palette.directColor7
Layout.alignment: Qt.AlignVCenter
implicitHeight: 36
topPadding: 8
bottomPadding: 8
placeholderText: "Search"
icon.name: "search"
visible: (notificationButton.visible && menuButton.visible)
}
}
}
leftPanel: Item {
anchors.fill: parent
anchors.margins: 16
RowLayout {
id: searchInputWrapper
width: parent.width
StatusNavigationPanelHeadline {
id: headline
Layout.alignment: Qt.AlignVCenter
text: "Chat"
}
StatusIconTabButton {
Item {
Layout.fillWidth: true
}
StatusRoundButton {
Layout.alignment: Qt.AlignVCenter
icon.name: "public-chat"
icon.color: Theme.palette.directColor1
icon.height: editBtn.icon.height
icon.width: editBtn.icon.width
implicitWidth: editBtn.implicitWidth
implicitHeight: editBtn.implicitHeight
type: StatusRoundButton.Type.Tertiary
StatusToolTip {
text: qsTr("Join public chats")
visible: parent.hovered
orientation: StatusToolTip.Orientation.Bottom
y: parent.height + 12
}
}
StatusIconTabButton {
id: editBtn
icon.name: "edit"
icon.color: Theme.palette.directColor1
checked: root.createChat
highlighted: checked
onClicked: {
root.createChat = !root.createChat;
}
StatusToolTip {
text: qsTr("Start chat")
visible: parent.hovered
orientation: StatusToolTip.Orientation.Bottom
y: parent.height + 12
}
}
}
Column {
StatusInput {
id: searchInput
anchors.top: searchInputWrapper.bottom
anchors.topMargin: 16
width: parent.width
maximumHeight: 36
topPadding: 8
bottomPadding: 8
placeholderText: "Search"
input.asset.name: "search"
}
Column {
width: parent.width
anchors.top: searchInput.bottom
anchors.topMargin: 16
anchors.horizontalCenter: parent.horizontalCenter
spacing: 8
StatusContactRequestsIndicatorListItem {
width: parent.width
anchors.horizontalCenter: parent.horizontalCenter
title: "Contact requests"
requestsCount: 3
sensor.onClicked: demoContactRequestsModal.open()
onClicked: demoContactRequestsModal.open()
}
StatusChatList {
width: parent.width
model: Models.demoChatListItems
highlightItem: !root.createChat
onChatItemUnmuted: {
@@ -140,58 +269,4 @@ StatusAppThreePanelLayout {
}
}
}
rightPanel: Item {
anchors.fill: parent
StatusChatToolBar {
width: parent.width
toolbarComponent: statusChatInfoButton
searchButton.visible: false
membersButton.visible: false
notificationCount: 1
onNotificationButtonClicked: notificationCount = 0
popupMenu: StatusPopupMenu {
id: contextMenu
StatusMenuItem {
text: "Mute Chat"
icon.name: "notification"
}
StatusMenuItem {
text: "Mark as Read"
icon.name: "checkmark-circle"
}
StatusMenuItem {
text: "Clear History"
icon.name: "close-circle"
}
StatusMenuSeparator {}
StatusMenuItem {
text: "Leave Chat"
icon.name: "arrow-right"
icon.width: 14
iconRotation: 180
type: StatusMenuItem.Type.Danger
}
}
Component {
id: statusChatInfoButton
StatusChatInfoButton {
width: Math.min(implicitWidth, parent.width)
title: "Amazing Funny Squirrel"
subTitle: "Contact"
icon.color: Theme.palette.miscColor7
type: StatusChatInfoButton.Type.OneToOneChat
pinnedMessagesCount: 1
}
}
}
}
}
+114 -109
View File
@@ -5,12 +5,12 @@ import QtQuick.Layouts 1.13
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Layout 0.1
import StatusQ.Components 0.1
import "../demoapp/data" 1.0
ScrollView {
StatusSectionLayout {
id: root
QtObject {
@@ -31,124 +31,129 @@ ScrollView {
console.info("Clicked community ID: " + communityId)
}
}
centerPanel: Item {
anchors.fill: parent
clip: true
StatusScrollView {
anchors.fill: parent
contentHeight: column.height + d.layoutVMargin
contentWidth: column.width + d.layoutHMargin
contentHeight: column.height + d.layoutVMargin
contentWidth: column.width + d.layoutHMargin
clip: true
ColumnLayout {
id: column
spacing: 18
ColumnLayout {
id: column
spacing: 18
StatusBaseText {
Layout.topMargin: d.layoutVMargin
Layout.leftMargin: d.layoutHMargin
text: qsTr("Find community")
font.weight: Font.Bold
font.pixelSize: d.titlePixelSize
color: Theme.palette.directColor1
}
// Tags definition - Now hidden - Out of scope
// TODO: Replace by `StatusListItemTagRow`
Row {
visible: d.tagsModel.count > 0
Layout.leftMargin: d.layoutHMargin
Layout.rightMargin: d.layoutHMargin
width: 1234 // by design
spacing: d.stylePadding/2
Repeater {
model: d.tagsModel
delegate: StatusListItemTag {
border.color: Theme.palette.baseColor2
color: "transparent"
height: 32
radius: 36
closeButtonVisible: false
icon.emoji: model.emoji
icon.height: 32
icon.width: icon.height
icon.color: "transparent"
icon.isLetterIdenticon: true
title: model.name
titleText.font.pixelSize: 15
titleText.color: Theme.palette.primaryColor1
StatusBaseText {
Layout.topMargin: d.layoutVMargin
Layout.leftMargin: d.layoutHMargin
text: qsTr("Find community")
font.weight: Font.Bold
font.pixelSize: d.titlePixelSize
color: Theme.palette.directColor1
}
}
}
StatusBaseText {
Layout.leftMargin: d.layoutHMargin
Layout.topMargin: 20
text: qsTr("Featured")
font.weight: Font.Bold
font.pixelSize: d.subtitlePixelSize
color: Theme.palette.directColor1
}
// Tags definition - Now hidden - Out of scope
// TODO: Replace by `StatusListItemTagRow`
Row {
visible: d.tagsModel.count > 0
Layout.leftMargin: d.layoutHMargin
Layout.rightMargin: d.layoutHMargin
width: 1234 // by design
spacing: d.stylePadding/2
GridLayout {
id: featuredGrid
Layout.leftMargin: d.layoutHMargin
columns: 3
columnSpacing: d.stylePadding
rowSpacing: d.stylePadding
Repeater {
model: d.featuredCommunitiesModel
delegate: StatusCommunityCard {
locale: "es"
communityId: model.communityId
loaded: model.available
logo: model.logo
name: model.name
description: model.description
members: model.members
popularity: model.popularity
communityColor: model.communityColor
categories: ListModel {
ListElement { name: "sport"; emoji: "🎾"}
ListElement { name: "food"; emoji: "🥑"}
ListElement { name: "privacy"; emoji: "👻"}
Repeater {
model: d.tagsModel
delegate: StatusListItemTag {
border.color: Theme.palette.baseColor2
color: "transparent"
height: 32
radius: 36
closeButtonVisible: false
asset.emoji: model.emoji
asset.height: 32
asset.width: asset.height
asset.color: "transparent"
asset.isLetterIdenticon: true
title: model.name
titleText.font.pixelSize: 15
titleText.color: Theme.palette.primaryColor1
}
}
onClicked: { d.navigateToCommunity(communityId) }
}
}
}
StatusBaseText {
Layout.leftMargin: d.layoutHMargin
Layout.topMargin: 20
text: qsTr("Popular")
font.weight: Font.Bold
font.pixelSize: d.subtitlePixelSize
color: Theme.palette.directColor1
}
StatusBaseText {
Layout.leftMargin: d.layoutHMargin
Layout.topMargin: 20
text: qsTr("Featured")
font.weight: Font.Bold
font.pixelSize: d.subtitlePixelSize
color: Theme.palette.directColor1
}
GridLayout {
Layout.leftMargin: d.layoutHMargin
columns: 3
columnSpacing: d.stylePadding
rowSpacing: d.stylePadding
GridLayout {
id: featuredGrid
Layout.leftMargin: d.layoutHMargin
columns: 3
columnSpacing: d.stylePadding
rowSpacing: d.stylePadding
Repeater {
model: d.popularCommunitiesModel
delegate: StatusCommunityCard {
locale: "es"
communityId: model.communityId
loaded: model.available
logo: model.logo
name: model.name
description: model.description
members: model.members
activeUsers: model.activeUsers
popularity: model.popularity
tokenLogo: model.tokenLogo
isPrivate: model.isPrivate
banner: model.banner
Repeater {
model: d.featuredCommunitiesModel
delegate: StatusCommunityCard {
locale: "es"
communityId: model.communityId
loaded: model.available
logo: model.logo
name: model.name
description: model.description
members: model.members
popularity: model.popularity
communityColor: model.communityColor
categories: ListModel {
ListElement { name: "sport"; emoji: "🎾"}
ListElement { name: "food"; emoji: "🥑"}
ListElement { name: "privacy"; emoji: "👻"}
}
onClicked: { d.navigateToCommunity(communityId) }
onClicked: { d.navigateToCommunity(communityId) }
}
}
}
StatusBaseText {
Layout.leftMargin: d.layoutHMargin
Layout.topMargin: 20
text: qsTr("Popular")
font.weight: Font.Bold
font.pixelSize: d.subtitlePixelSize
color: Theme.palette.directColor1
}
GridLayout {
Layout.leftMargin: d.layoutHMargin
columns: 3
columnSpacing: d.stylePadding
rowSpacing: d.stylePadding
Repeater {
model: d.popularCommunitiesModel
delegate: StatusCommunityCard {
locale: "es"
communityId: model.communityId
loaded: model.available
logo: model.logo
name: model.name
description: model.description
members: model.members
activeUsers: model.activeUsers
popularity: model.popularity
tokenLogo: model.tokenLogo
isPrivate: model.isPrivate
banner: model.banner
onClicked: { d.navigateToCommunity(communityId) }
}
}
}
}
}
+110 -79
View File
@@ -1,5 +1,6 @@
import QtQuick 2.12
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.12
import StatusQ.Core 0.1
import StatusQ.Popups 0.1
@@ -10,7 +11,7 @@ import StatusQ.Core.Theme 0.1
import "data" 1.0
StatusAppThreePanelLayout {
StatusSectionLayout {
id: root
property string communityDetailModalTitle: ""
@@ -22,6 +23,101 @@ StatusAppThreePanelLayout {
color: SplitHandle.pressed ? Theme.palette.baseColor2
: (SplitHandle.hovered ? Qt.darker(Theme.palette.baseColor5, 1.1) : "transparent")
}
headerContent: RowLayout {
id: statusToolBar
StatusFlatRoundButton {
id: searchButton
Layout.alignment: Qt.AlignLeft
Layout.leftMargin: padding
icon.name: "search"
type: StatusFlatRoundButton.Type.Secondary
// initializing the tooltip
tooltip.text: qsTr("Search")
tooltip.orientation: StatusToolTip.Orientation.Bottom
tooltip.y: parent.height + 12
onClicked: {
searchButton.highlighted = !searchButton.highlighted;
searchPopup.setSearchSelection(communityDetailModalTitle,
"",
communityDetailModalImage);
searchPopup.open();
}
}
StatusChatInfoButton {
Layout.preferredWidth: Math.min(implicitWidth, parent.width)
Layout.fillHeight: true
title: "general"
subTitle: "Community Chat"
asset.color: Theme.palette.miscColor6
type: StatusChatInfoButton.Type.CommunityChat
}
Item {
Layout.fillWidth: true
}
StatusFlatRoundButton {
id: membersButton
icon.name: "group-chat"
type: StatusFlatRoundButton.Type.Secondary
// initializing the tooltip
tooltip.text: qsTr("Members")
tooltip.orientation: StatusToolTip.Orientation.Bottom
tooltip.y: parent.height + 12
onClicked: {
membersButton.highlighted = !membersButton.highlighted;
root.showRightPanel = !root.showRightPanel;
}
}
StatusSearchPopup {
id: searchPopup
searchOptionsPopupMenu: searchPopupMenu
onAboutToHide: {
if (searchPopupMenu.visible) {
searchPopupMenu.close();
}
//clear menu
for (var i = 2; i < searchPopupMenu.count; i++) {
searchPopupMenu.removeItem(searchPopupMenu.takeItem(i));
}
}
onClosed: {
statusToolBar.searchButton.highlighted = false
searchPopupMenu.dismiss();
}
onSearchTextChanged: {
if (searchPopup.searchText !== "") {
searchPopup.loading = true;
searchModelSimTimer.start();
} else {
searchPopup.searchResults = [];
searchModelSimTimer.stop();
}
}
Timer {
id: searchModelSimTimer
interval: 500
onTriggered: {
if (searchPopup.searchText.startsWith("c")) {
searchPopup.searchResults = Models.searchResultsA;
} else {
searchPopup.searchResults = Models.searchResultsB;
}
searchPopup.loading = false;
}
}
}
StatusSearchLocationMenu {
id: searchPopupMenu
searchPopup: searchPopup
locationModel: Models.optionsModel
}
}
leftPanel: Item {
id: leftPanel
@@ -33,8 +129,9 @@ StatusAppThreePanelLayout {
chatInfoButton.title: "CryptoKitties"
chatInfoButton.subTitle: "128 Members"
chatInfoButton.image.source: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
chatInfoButton.icon.color: Theme.palette.miscColor6
chatInfoButton.asset.isImage: true
chatInfoButton.asset.name: "qrc:/demoapp/data/profile-image-1.jpeg"
chatInfoButton.asset.color: Theme.palette.miscColor6
chatInfoButton.onClicked: { chatInfoButtonClicked(); }
popupMenu: StatusPopupMenu {
@@ -59,7 +156,7 @@ StatusAppThreePanelLayout {
}
}
ScrollView {
StatusScrollView {
id: scrollView
anchors.top: statusChatInfoToolBar.bottom
@@ -164,79 +261,11 @@ StatusAppThreePanelLayout {
}
centerPanel: Item {
StatusChatToolBar {
id: statusChatToolBar
width: parent.width
toolbarComponent: statusChatInfoButton
onSearchButtonClicked: {
searchButton.highlighted = !searchButton.highlighted;
searchPopup.setSearchSelection(communityDetailModalTitle,
"",
communityDetailModalImage);
searchPopup.open();
}
membersButton.onClicked: membersButton.highlighted = !membersButton.highlighted
onMembersButtonClicked: {
root.showRightPanel = !root.showRightPanel;
}
Component {
id: statusChatInfoButton
StatusChatInfoButton {
width: Math.min(implicitWidth, parent.width)
title: "general"
subTitle: "Community Chat"
icon.color: Theme.palette.miscColor6
type: StatusChatInfoButton.Type.CommunityChat
}
}
}
StatusSearchPopup {
id: searchPopup
searchOptionsPopupMenu: searchPopupMenu
onAboutToHide: {
if (searchPopupMenu.visible) {
searchPopupMenu.close();
}
//clear menu
for (var i = 2; i < searchPopupMenu.count; i++) {
searchPopupMenu.removeItem(searchPopupMenu.takeItem(i));
}
}
onClosed: {
statusChatToolBar.searchButton.highlighted = false
searchPopupMenu.dismiss();
}
onSearchTextChanged: {
if (searchPopup.searchText !== "") {
searchPopup.loading = true;
searchModelSimTimer.start();
} else {
searchPopup.searchResults = [];
searchModelSimTimer.stop();
}
}
Timer {
id: searchModelSimTimer
interval: 500
onTriggered: {
if (searchPopup.searchText.startsWith("c")) {
searchPopup.searchResults = Models.searchResultsA;
} else {
searchPopup.searchResults = Models.searchResultsB;
}
searchPopup.loading = false;
}
}
}
StatusSearchLocationMenu {
id: searchPopupMenu
searchPopup: searchPopup
locationModel: Models.optionsModel
anchors.fill: parent
StatusBaseText {
anchors.centerIn: parent
font.pixelSize: 15
text: qsTr("Community content here")
}
}
@@ -273,8 +302,10 @@ StatusAppThreePanelLayout {
isVerified: model.isVerified
isUntrustworthy: model.isUntrustworthy
isContact: model.isContact
image.source: model.icon
image.isIdenticon: false
asset.name: model.icon
asset.isImage: (asset.name !== "")
asset.isLetterIdenticon: (asset.name === "")
asset.imgIsIdenticon: false
status: model.onlineStatus
}
}
@@ -3,11 +3,12 @@ import QtQuick.Controls 2.14
import StatusQ.Components 0.1
import StatusQ.Layout 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import "data" 1.0
StatusAppTwoPanelLayout {
StatusSectionLayout {
id: root
leftPanel: Item {
@@ -21,7 +22,7 @@ StatusAppTwoPanelLayout {
text: "Profile"
}
ScrollView {
StatusScrollView {
anchors.top: profileHeadline.bottom
anchors.topMargin: 16
anchors.bottom: parent.bottom
@@ -40,7 +41,7 @@ StatusAppTwoPanelLayout {
model: Models.demoProfileGeneralMenuItems
delegate: StatusNavigationListItem {
title: model.title
icon.name: model.icon
asset.name: model.icon
}
}
@@ -50,7 +51,7 @@ StatusAppTwoPanelLayout {
model: Models.demoProfileSettingsMenuItems
delegate: StatusNavigationListItem {
title: model.title
icon.name: model.icon
asset.name: model.icon
}
}
@@ -64,7 +65,7 @@ StatusAppTwoPanelLayout {
model: Models.demoProfileOtherMenuItems
delegate: StatusNavigationListItem {
title: model.title
icon.name: model.icon
asset.name: model.icon
}
}
}
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

+155
View File
@@ -0,0 +1,155 @@
import QtQuick 2.14
import QtQuick.Layouts 1.14
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Components 0.1
import StatusQ.Core.Utils 0.1
import SortFilterProxyModel 0.2
ColumnLayout {
id: root
RowLayout {
Layout.fillWidth: true
StatusIconTextButton {
id: sortBtn
property int sortOrder: -1
statusIcon: {
if (sortOrder == Qt.AscendingOrder) return "chevron-down"
if (sortOrder == Qt.DescendingOrder) return "chevron-up"
return "remove"
}
onClicked: {
var st = sortOrder + 1
sortOrder = st > 1 ? -1 : st
}
}
StatusInput {
id: searchInput
Layout.fillWidth: true
input.asset.name: "search"
placeholderText: "nickname.."
}
StatusIconTabButton {
id: contactBtn
icon.name: "tiny/tiny-contact"
identicon.asset.color: Theme.palette.primaryColor1
onClicked: highlighted = !highlighted
}
StatusIconTabButton {
id: verifiedBtn
icon.name: "tiny/tiny-checkmark"
identicon.asset.color: Theme.palette.primaryColor1
onClicked: highlighted = !highlighted
}
}
ListView {
Layout.fillWidth: true
implicitHeight: contentItem.childrenRect.height
spacing: 4
model: SortFilterProxyModel {
sourceModel: d.users
sorters: StringSorter {
enabled: sortBtn.sortOrder !== -1
roleName: "nick"
sortOrder: sortBtn.sortOrder
}
filters: [
ExpressionFilter {
expression: model.nick.startsWith(searchInput.text)
},
AllOf {
enabled: contactBtn.highlighted || verifiedBtn.highlighted
ValueFilter {
enabled: contactBtn.highlighted
roleName: "isContact"
value: true
}
ValueFilter {
enabled: verifiedBtn.highlighted
roleName: "isVerified"
value: true
}
}
]
}
delegate: StatusMemberListItem {
width: parent.width
userName: model.name
nickName: model.nick
isVerified: model.isVerified
isContact: model.isContact
asset.isLetterIdenticon: true
}
}
QtObject {
id: d
readonly property ListModel users: ListModel {
ListElement {
name: "Richard"
nick: "Ricky"
isVerified: true
isContact: true
}
ListElement {
name: "Susan"
nick: "Sue"
isVerified: false
isContact: false
}
ListElement {
name: "Edward"
nick: "Ed"
isVerified: true
isContact: false
}
ListElement {
name: "Toomas"
nick: "Tommy"
isVerified: false
isContact: false
}
ListElement {
name: "Elizabeth"
nick: "Bess"
isVerified: true
isContact: true
}
ListElement {
name: "Thomas"
nick: "Tom"
isVerified: false
isContact: true
}
ListElement {
name: "Fernando"
nick: "Alonso"
isVerified: false
isContact: true
}
ListElement {
name: "Alexander"
nick: "Alex"
isVerified: true
isContact: false
}
}
}
}
-6
View File
@@ -1,6 +0,0 @@
#include "handler.h"
Handler::Handler(QObject *parent) : QObject(parent)
{
}
-16
View File
@@ -1,16 +0,0 @@
#ifndef HANDLER_H
#define HANDLER_H
#include <QObject>
class Handler : public QObject
{
Q_OBJECT
public:
explicit Handler(QObject *parent = nullptr);
signals:
void restartQml();
};
#endif // HANDLER_H
+6
View File
@@ -4,6 +4,8 @@
#include "sandboxapp.h"
#include <qqmlsortfilterproxymodeltypes.h>
int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
@@ -12,6 +14,10 @@ int main(int argc, char *argv[])
SandboxApp app(argc, argv);
qqsfpm::registerTypes();
qputenv("QT_QUICK_CONTROLS_HOVER_ENABLED", QByteArrayLiteral("1"));
app.setOrganizationName("Status");
app.setOrganizationDomain("status.im");
app.setApplicationName("Sandbox");
+287 -209
View File
@@ -4,6 +4,7 @@ import QtQuick.Controls 2.14
import QtGraphicalEffects 1.13
import QtQuick.Layouts 1.14
import Qt.labs.settings 1.0
import QtQml.Models 2.14
import Sandbox 0.1
@@ -14,6 +15,8 @@ import StatusQ.Components 0.1
import StatusQ.Layout 0.1
import StatusQ.Platform 0.1
import SortFilterProxyModel 0.2
import "demoapp/data" 1.0
StatusWindow {
@@ -44,7 +47,8 @@ StatusWindow {
readonly property int nodeManagement: 4
readonly property int profileSettings: 5
readonly property int apiDocumentation: 100
readonly property int demoApp: 101
readonly property int examples: 101
readonly property int demoApp: 102
}
function setActiveItem(sectionId) {
@@ -59,11 +63,11 @@ StatusWindow {
}
}
StatusAppLayout {
StatusMainLayout {
id: appLayout
anchors.fill: parent
appNavBar: StatusAppNavBar {
leftPanel: StatusAppNavBar {
height: rootWindow.height
communityTypeRole: "sectionType"
@@ -87,41 +91,48 @@ StatusWindow {
if(model.sectionType === appSectionType.apiDocumentation)
{
stackView.push(libraryDocumentationCmp)
rootWindow.setActiveItem(sectionId)
}
else if(model.sectionType === appSectionType.examples)
{
stackView.push(examplesCmp)
}
else if(model.sectionType === appSectionType.demoApp)
{
stackView.push(demoAppCmp)
rootWindow.setActiveItem(model.sectionId)
}
rootWindow.setActiveItem(model.sectionId)
}
}
}
appView: StackView {
id: stackView
rightPanel: Item {
anchors.fill: parent
initialItem: libraryDocumentationCmp
}
ThemeSwitch {
anchors.top: parent.top
anchors.topMargin: 32
anchors.right: parent.right
anchors.rightMargin: 32
lightThemeEnabled: storeSettings.lightTheme
onLightThemeEnabledChanged: {
Theme.palette = lightThemeEnabled ? rootWindow.darkTheme : rootWindow.lightTheme
storeSettings.lightTheme = lightThemeEnabled
StackView {
id: stackView
anchors.fill: parent
initialItem: libraryDocumentationCmp
}
ThemeSwitch {
anchors.top: parent.top
anchors.topMargin: 32
anchors.right: parent.right
anchors.rightMargin: 32
lightThemeEnabled: storeSettings.lightTheme
onLightThemeEnabledChanged: {
Theme.palette = lightThemeEnabled ? rootWindow.darkTheme : rootWindow.lightTheme
storeSettings.lightTheme = lightThemeEnabled
}
}
}
}
Component {
id: libraryDocumentationCmp
StatusAppTwoPanelLayout {
StatusSectionLayout {
id: mainPageView
showHeader: false
function page(name, fillPage) {
storeSettings.fillPage = fillPage ? true : false
@@ -132,205 +143,220 @@ StatusWindow {
storeSettings.fillPage = false
}
leftPanel: Item {
leftPanel: StatusScrollView {
anchors.fill: parent
ScrollView {
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
contentHeight: navigation.height + 56
contentWidth: navigation.width
clip: true
Column {
id: navigation
anchors.top: parent.top
anchors.topMargin: 48
anchors.horizontalCenter: parent.horizontalCenter
spacing: 0
anchors.topMargin: 48
StatusListSectionHeadline { text: "StatusQ.Core" }
StatusNavigationListItem {
title: "Icons"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.control(title);
}
Column {
id: navigation
spacing: 0
StatusListSectionHeadline { text: "StatusQ.Layout" }
StatusNavigationListItem {
title: "Layouts"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.control(title.substring(0, title.length - 1));
}
StatusListSectionHeadline { text: "StatusQ.Core" }
StatusNavigationListItem {
title: "Icons"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.control(title);
}
StatusListSectionHeadline { text: "StatusQ.Controls" }
StatusNavigationListItem {
title: "Buttons"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.control(title);
}
StatusNavigationListItem {
title: "StatusSwitchTab"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page("StatusTabSwitch");
}
StatusNavigationListItem {
title: "StatusChatCommandButton"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "Controls"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.control(title);
}
StatusNavigationListItem {
title: "StatusTabBarButton"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusTabBarIconButton"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusInput"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusSelect"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusAccountSelector"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusAssetSelector"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusColorSelector"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusWalletColorButton"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusWalletColorSelect"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusPasswordStrengthIndicator"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusPinInput"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusListSectionHeadline { text: "StatusQ.Components" }
StatusNavigationListItem {
title: "StatusAddress"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "List Items"
selected: viewLoader.source.toString().includes(title.replace(/\s+/g, ''))
onClicked: mainPageView.control(title.replace(/\s+/g, ''));
}
StatusNavigationListItem {
title: "StatusChatInfoToolBar"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "Others"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.control(title);
}
StatusNavigationListItem {
title: "StatusExpandableItem"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page("StatusExpandableSettingsItem");
}
StatusNavigationListItem {
title: "StatusTagSelector"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusToastMessage"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusWizardStepper"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusListPicker"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusCommunityCard"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusListSectionHeadline { text: "StatusQ.Popup" }
StatusNavigationListItem {
title: "StatusPopupMenu"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusListSectionHeadline { text: "StatusQ.Layout" }
StatusNavigationListItem {
title: "Layouts"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.control(title.substring(0, title.length - 1));
}
StatusNavigationListItem {
title: "StatusModal"
selected: viewLoader.source.toString().includes("Popups")
onClicked: mainPageView.control("Popups");
}
StatusListSectionHeadline { text: "StatusQ.Platform" }
StatusNavigationListItem {
title: "StatusMacNotification"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusColorSelectorGrid"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusImageCropPanel"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title, true);
}
StatusNavigationListItem {
title: "StatusColorSpace"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title, true);
}
StatusListSectionHeadline { text: "StatusQ.Controls" }
StatusNavigationListItem {
title: "Buttons"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.control(title);
}
StatusNavigationListItem {
title: "StatusSwitchTab"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page("StatusTabSwitch");
}
StatusNavigationListItem {
title: "StatusChatCommandButton"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "Controls"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.control(title);
}
StatusNavigationListItem {
title: "StatusTabBarButton"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusTabBarIconButton"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusInput"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusTextArea"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusSelect"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusComboBox"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusAccountSelector"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusColorSelector"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusWalletColorButton"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusWalletColorSelect"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusPasswordStrengthIndicator"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusPinInput"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusListSectionHeadline { text: "StatusQ.Components" }
StatusNavigationListItem {
title: "StatusAddress"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "List Items"
selected: viewLoader.source.toString().includes(title.replace(/\s+/g, ''))
onClicked: mainPageView.control(title.replace(/\s+/g, ''));
}
StatusNavigationListItem {
title: "StatusChatInfoToolBar"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "Others"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.control(title);
}
StatusNavigationListItem {
title: "StatusExpandableItem"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page("StatusExpandableSettingsItem");
}
StatusNavigationListItem {
title: "StatusTagSelector"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusToastMessage"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusWizardStepper"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusListPicker"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusCommunityCard"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusCommunityTags"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusItemSelector"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title, true);
}
StatusListSectionHeadline { text: "StatusQ.Popup" }
StatusNavigationListItem {
title: "StatusPopupMenu"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusModal"
selected: viewLoader.source.toString().includes("Popups")
onClicked: mainPageView.control("Popups");
}
StatusNavigationListItem {
title: "StatusDialog"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusListSectionHeadline { text: "StatusQ.Platform" }
StatusNavigationListItem {
title: "StatusMacNotification"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusColorSelectorGrid"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title);
}
StatusNavigationListItem {
title: "StatusImageCropPanel"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title, true);
}
StatusNavigationListItem {
title: "StatusColorSpace"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title, true);
}
StatusNavigationListItem {
title: "StatusCard"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title, true);
}
}
}
rightPanel: Item {
id: rightPanel
centerPanel: Item {
id: centerPanel
anchors.fill: parent
ScrollView {
StatusScrollView {
visible: !storeSettings.fillPage
anchors.fill: parent
anchors.topMargin: 64
@@ -340,7 +366,7 @@ StatusWindow {
Item {
id: pageWrapper
width: rightPanel.width
width: centerPanel.width
anchors.top: parent.top
height: Math.max(rootWindow.height, viewLoader.height + 128)
scale: rootWindow.factor
@@ -395,6 +421,57 @@ StatusWindow {
}
}
Component {
id: examplesCmp
StatusSectionLayout {
id: examplesView
showHeader: false
function example(name) {
examplesLoader.source = Qt.resolvedUrl("./examples/" + name + ".qml")
storeSettings.selectedExample = examplesLoader.source
}
readonly property string defaultExampleSource: example("FilteringSorting")
leftPanel: StatusScrollView {
id: examplesLeftPanel
anchors.fill: parent
anchors.topMargin: 48
ColumnLayout {
width: examplesLeftPanel.availableWidth
spacing: 0
StatusNavigationListItem {
Layout.fillWidth: true
title: "FilteringSorting"
selected: examplesLoader.source.toString().includes(title)
onClicked: examplesView.example(title)
}
}
}
centerPanel: Item {
anchors.fill: parent
StatusScrollView {
id: examplesCenterPanel
anchors.fill: parent
anchors.margins: 64
anchors.topMargin: anchors.margins + 32
Loader {
id: examplesLoader
width: examplesCenterPanel.availableWidth
source: storeSettings.selectedExample !== "" ? storeSettings.selectedExample : examplesView.defaultExampleSource
}
}
}
}
}
Component {
id: demoAppCmp
@@ -489,6 +566,7 @@ StatusWindow {
Settings {
id: storeSettings
property string selected: ""
property string selectedExample: ""
property bool lightTheme: true
property bool fillPage: false
}
+51 -47
View File
@@ -8,57 +8,61 @@ import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Popups 0.1
Column {
spacing: 8
StatusAccountSelector {
id: accountSelector
accounts: ListModel {
ListElement {
name: "Pascal"
address: "0x1234567891011"
path: ""
color: "red"
publicKey: ""
walletType: "generated"
isChat: ""
currencyBalance: "1199.02"
assets: []
}
ListElement {
name: "Boris"
address: "0x123"
path: ""
color: "red"
publicKey: ""
walletType: "generated"
isChat: ""
currencyBalance: "0"
assets: []
}
ListElement {
name: "Alexandra"
address: "0x123"
path: ""
color: "yellow"
publicKey: ""
walletType: "generated"
isChat: ""
currencyBalance: "0"
assets: []
}
ListElement {
name: "Khushboo"
address: "0x123"
path: ""
color: "blue"
publicKey: ""
walletType: "generated"
isChat: ""
currencyBalance: "0"
assets: []
}
id: selector1
width: 300
accounts: accountsModel
}
ListModel {
id: accountsModel
ListElement {
name: "Pascal"
address: "0x1234567891011"
path: ""
color: "red"
publicKey: ""
walletType: "generated"
isChat: ""
currencyBalance: "1199.02"
assets: []
}
ListElement {
name: "Boris"
address: "0x123"
path: ""
color: "red"
publicKey: ""
walletType: "generated"
isChat: ""
currencyBalance: "42.42"
assets: []
}
ListElement {
name: "Alexandra"
address: "0x123"
path: ""
color: "yellow"
publicKey: ""
walletType: "generated"
isChat: ""
currencyBalance: "0"
assets: []
}
ListElement {
name: "Khushboo"
address: "0x123"
path: ""
color: "blue"
publicKey: ""
walletType: "watch" // Will be automatically filtered by StatusAccountSelector
isChat: ""
currencyBalance: "0"
assets: []
}
}
}
+82 -9
View File
@@ -2,24 +2,97 @@ import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import StatusQ.Core 0.1
import StatusQ.Components 0.1
import Sandbox 0.1
Column {
spacing: 8
Item {
id: root
StatusAddress {
text: "0x9ce0056c5fc6bb9459a4dcfa35eaad8c1fee5ce9"
}
implicitWidth: mainLayout.implicitWidth
implicitHeight: mainLayout.implicitHeight
Item {
width: 200
height: childrenRect.height
GridLayout {
id: mainLayout
columns: 2
anchors.fill: parent
columnSpacing: 15
rowSpacing: 8
StatusBaseText { text: "StatusAddress\nsimple" }
StatusAddress {
text: "0x9ce0056c5fc6bb9459a4dcfa35eaad8c1fee5ce9"
}
StatusBaseText { text: "StatusAddress\nclick-expandable" }
StatusAddress {
text: "0x9ce0056c5fc6bb9459a4dcfa35eaad8c1fee5ce9"
Layout.preferredWidth: 200
expandable: true
width: parent.width
}
StatusBaseText { text: `StatusAddressPanel\nfont.pixelSize: 13, copyable, no frame`}
StatusAddressPanel {
address: "0xDC2c4826f6C56F61C1b9cC6Bb531d0Fe45402fC9"
font.pixelSize: 13
font.weight: Font.Normal
showFrame: false
onDoCopy: copyAction.text = address
}
StatusBaseText { text: `StatusAddressPanel\ncompact; width ${simpleAddressPanel.width}px ${simpleAddressPanel.height}px`}
StatusAddressPanel {
id: simpleAddressPanel
address: "0xd8593DEACe2f44dF35dd23fD2BAFC2daeC2ae033"
showCopy: false
expanded: false
onDoCopy: copyAction.text = address
expandable: true
}
StatusBaseText { text: "StatusAddressPanel\ncopy-icon, non-expandable" }
StatusAddressPanel {
address: "0xDd5A0755e99D66a583253372B569231968A6CF7b"
onDoCopy: copyAction.text = address
}
StatusBaseText { text: "StatusAddressPanel\ncopy hiden" }
StatusAddressPanel {
address: "0xd2D44C2A1E78975506e474Ecdc7E4F272D7e9A6c"
autHideCopyIcon: true
onDoCopy: copyAction.text = address
expandable: true
}
StatusBaseText { text: "StatusAddressPanel\ncopy hiden, non-expandable" }
StatusAddressPanel {
address: "0xd2a44BA31E78975506e474Ecdc7E4F272D7F3BC5"
autHideCopyIcon: true
expanded: false
onDoCopy: copyAction.text = address
}
Rectangle {
color: "lightblue"
Layout.fillWidth: true
Layout.columnSpan: mainLayout.columns
Layout.preferredHeight: 2
}
StatusBaseText {
text: qsTr("Copy Action: ")
}
StatusBaseText {
id: copyAction
}
}
}
-40
View File
@@ -1,40 +0,0 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Popups 0.1
import Sandbox 0.1
Column {
spacing: 8
StatusAssetSelector {
getCurrencyBalanceString: function (currencyBalance) {
return currencyBalance.toFixed(2) + " USD"
}
tokenAssetSourceFn: function (symbol) {
return "../../assets/img/icons/snt.svg"
}
assets: ListModel {
ListElement {
address: "0x1234"
name: "Status Network Token"
balance: "20"
symbol: "SNT"
currencyBalance: 9992.01
}
ListElement {
address: "0x1234"
name: "DAI Token"
balance: "15"
symbol: "DAI"
currencyBalance: 20.00001
}
}
}
}
+239
View File
@@ -0,0 +1,239 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import Sandbox 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Utils 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Popups 0.1
import StatusQ.Components 0.1
Item {
ColumnLayout {
id: layout
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
spacing: 20
RowLayout {
Layout.fillWidth: true
StatusCard {
id: card
Layout.alignment: Qt.AlignVCenter
primaryText: "Mainnet"
secondaryText: state === "unavailable" ? "No Gas" : "75"
tertiaryText: state === "unpreferred" ? "UNPREFERRED" : "BALANCE: " + 250
cardIconName: "status"
advancedInputText: "75"
disabledText: "Disabled"
}
StatusComboBox {
Layout.alignment: Qt.AlignVCenter
Layout.maximumWidth: 200
label: "Card State"
onCurrentValueChanged: card.state = currentValue
model: ListModel {
ListElement {
name: "default"
}
ListElement {
name: "unavailable"
}
ListElement {
name: "error"
}
ListElement {
name: "unpreferred"
}
}
}
StatusCheckBox {
Layout.alignment: Qt.AlignVCenter
text: "advancedMode"
font.family: Theme.palette.monoFont.name
onClicked: {
card.advancedMode = checked
}
}
}
Rectangle {
height: 1
width: 700
color: "black"
}
// Below is an example on how to implement the network routing using StatusCard and Canvas, also the function in Utils to draw an arrow
Row {
id: cards
spacing: 200
Column {
id: leftColumn
spacing: 20
Repeater {
model: fromNetworksList
StatusCard {
primaryText: name
secondaryText: balance === 0 ? "No Balance" : !hasGas ? "No Gas" : tokensToSend
tertiaryText: "BALANCE: " + balance
state: balance === 0 || !hasGas ? "unavailable" : "default"
cardIconName: iconName
advancedMode: card.advancedMode
advancedInputText: tokensToSend
disabledText: "Disabled"
}
}
}
Column {
id: rightColumn
spacing: 20
Repeater {
model: toNetworksList
StatusCard {
primaryText: name
secondaryText: tokensToReceive
tertiaryText: ""
state: preferred ? "default" : "unprefeered"
cardIconName: iconName
opacity: preferred ? 1 : 0
advancedMode: card.advancedMode
advancedInputText: tokensToReceive
disabledText: "Disabled"
}
}
}
}
}
Canvas {
id: canvas
x: layout.x + leftColumn.x
y: cards.y
width: cards.width
height: cards.height
function clear() {
var ctx = getContext("2d");
ctx.reset()
}
onPaint: {
// Get the canvas context
var ctx = getContext("2d");
for(var i = 0; i< fromNetworksList.count; i++) {
if(fromNetworksList.get(i).routedTo !== "") {
for(var j = 0; j< toNetworksList.count; j++) {
if(fromNetworksList.get(i).routedTo === toNetworksList.get(j).name) {
Utils.drawArrow(ctx, leftColumn.children[i].x + leftColumn.children[i].width,
leftColumn.children[i].y + leftColumn.children[i].height/2,
rightColumn.x + rightColumn.children[j].x,
rightColumn.children[j].y + rightColumn.children[j].height/2,
'#627EEA')
}
}
}
}
}
}
ListModel {
id: toNetworksList
ListElement {
name: "Mainnet"
iconName: "status"
tokensToReceive: 75
preferred: true
}
ListElement {
name: "Aztec"
iconName: "status"
tokensToReceive: 0
preferred: false
}
ListElement {
name: "Hermez"
iconName: "status"
tokensToReceive: 75
preferred: true
}
ListElement {
name: "Loppring"
iconName: "status"
tokensToReceive: 0
preferred: true
}
ListElement {
name: "Optimism"
iconName: "status"
tokensToReceive: 100
preferred: true
}
ListElement {
name: "zkSync"
iconName: "status"
tokensToReceive: 0
preferred: false
}
}
ListModel {
id: fromNetworksList
ListElement {
name: "Mainnet"
iconName: "status"
tokensToSend: 75
balance: 75
routedTo: "Mainnet"
hasGas: true
}
ListElement {
name: "Aztec"
iconName: "status"
tokensToSend: 0
balance: 75
routedTo: ""
hasGas: false
}
ListElement {
name: "Hermez"
iconName: "status"
tokensToSend: 75
balance: 75
routedTo: "Hermez"
hasGas: true
}
ListElement {
name: "Loppring"
iconName: "status"
tokensToSend: 0
balance: 0
routedTo: ""
hasGas: false
}
ListElement {
name: "Optimism"
iconName: "status"
tokensToSend: 75
balance: 75
routedTo: "Optimism"
hasGas: true
}
ListElement {
name: "zkSync"
iconName: "status"
tokensToSend: 25
balance: 25
routedTo: "Optimism"
hasGas: true
}
}
}
+3 -2
View File
@@ -14,8 +14,9 @@ GridLayout {
StatusChatInfoToolBar {
chatInfoButton.title: "Cryptokitties"
chatInfoButton.subTitle: "128 Members"
chatInfoButton.image.source: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
chatInfoButton.icon.color: Theme.palette.miscColor6
chatInfoButton.asset.isImage: true
chatInfoButton.asset.name: "qrc:/demoapp/data/profile-image-1.jpeg"
chatInfoButton.asset.color: Theme.palette.miscColor6
popupMenu: StatusPopupMenu {
+1 -1
View File
@@ -8,7 +8,7 @@ import StatusQ.Controls 0.1
import Sandbox 0.1
Column {
Row {
spacing: 8
StatusColorSelector {
+72
View File
@@ -0,0 +1,72 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Popups 0.1
import Sandbox 0.1
Column {
spacing: 20
ListModel {
id: commmonModel
ListElement {
name: "Pascal"
}
ListElement {
name: "Khushboo"
}
ListElement {
name: "Alexandra"
}
ListElement {
name: "Eric"
}
}
StatusComboBox {
id: combobox
label: "ComboBox"
model: commmonModel
}
StatusComboBox {
id: comboBox1
label: "ComboBox with custom delegate"
model: commmonModel
delegate: StatusItemDelegate {
width: comboBox1.control.width
highlighted: comboBox1.control.highlightedIndex === index
text: modelData
font: comboBox1.control.font
icon {
name: "filled-account"
color: Theme.palette.primaryColor1
}
enabled: index != 2
}
}
StatusComboBox {
model: commmonModel
label: "Disabled ComboBox"
enabled: false
}
StatusComboBox {
model: commmonModel
label: "ComboBox with validation error"
validationError: "Validation failed example"
}
StatusComboBox {
model: commmonModel
label: "Mirrored ComboBox"
LayoutMirroring.enabled: true
}
}
+83
View File
@@ -0,0 +1,83 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Components 0.1
import Sandbox 0.1
import "../demoapp/data" 1.0
Item {
property int cntSelectedTags: 0
property int maxSelectedTags: 4
property ListModel tagsModel: ListModel {}
Component.onCompleted: {
tagsModel.clear();
for (const key of Object.keys(Models.communityTags)) {
tagsModel.append({ name: key, emoji: Models.communityTags[key], selected: false });
}
}
ColumnLayout {
id: column
anchors.centerIn: parent
width: 600
height: 500
spacing: 20
StatusInput {
id: tagsFilter
leftPadding: 0
rightPadding: 0
label: qsTr("Select tags that will fit your Community")
input.asset.name: "search"
placeholderText: qsTr("Search tags")
Layout.fillWidth: true
}
StatusCommunityTags {
filterString: tagsFilter.text
model: tagsModel
enabled: cntSelectedTags < maxSelectedTags
onClicked: {
cntSelectedTags++;
item.selected = true;
}
Layout.fillWidth: true
}
RowLayout {
StatusBaseText {
text: qsTr("Selected tags")
font.pixelSize: 15
Layout.fillWidth: true
}
StatusBaseText {
text: cntSelectedTags + "/" + maxSelectedTags
color: Theme.palette.baseColor1
font.pixelSize: 13
}
}
StatusCommunityTags {
model: tagsModel
showOnlySelected: true
onClicked: {
cntSelectedTags--;
item.selected = false;
}
Layout.fillWidth: true
}
Item {
Layout.fillHeight: true
}
}
}
+282
View File
@@ -0,0 +1,282 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import QtQml.Models 2.14
import StatusQ.Core 0.1
import StatusQ.Controls 0.1
import StatusQ.Popups.Dialog 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Components 0.1
ColumnLayout {
id: root
StatusButton {
text: "Content"
onClicked: contentDialog.open()
StatusDialog {
id: contentDialog
standardButtons: Dialog.ApplyRole
StatusBaseText {
anchors.fill: parent
text: "Content"
}
}
}
StatusButton {
text: "Title and content"
onClicked: titleContentDialog.open()
StatusDialog {
id: titleContentDialog
title: "Title"
StatusBaseText {
anchors.fill: parent
text: "Content"
}
}
}
StatusButton {
text: "No buttons"
onClicked: noButtonsDialog.open()
StatusDialog {
id: noButtonsDialog
title: "No buttons"
standardButtons: Dialog.NoButton
StatusBaseText {
anchors.fill: parent
text: "Content"
}
}
}
StatusButton {
text: "Long title"
onClicked: longTitleDialog.open()
StatusDialog {
id: longTitleDialog
title: "Long title long title Long title long title Long title long title"
StatusBaseText {
anchors.fill: parent
text: "Content"
}
}
}
StatusButton {
text: "Long title elided"
onClicked: longTitleElidedDialog.open()
StatusDialog {
id: longTitleElidedDialog
title: "Long title long title Long title long title Long title long title"
width: 400
StatusBaseText {
anchors.fill: parent
text: "Content"
}
}
}
StatusButton {
text: "Title subtitle"
onClicked: titleSubtitleDialog.open()
StatusDialog {
id: titleSubtitleDialog
title: "This title will be ignored"
header: StatusDialogHeader {
headline.title: "Title"
headline.subtitle: "Subtitle"
actions.closeButton.onClicked: titleSubtitleDialog.close()
}
StatusBaseText {
anchors.fill: parent
text: "Content"
}
}
}
StatusButton {
text: "Auto adjustable"
onClicked: autoAdjustableDialog.open()
StatusDialog {
id: autoAdjustableDialog
header: StatusDialogHeader {
headline.title: "Dialog size will auto adapt"
headline.subtitle: "To conent size"
actions.closeButton.onClicked: autoAdjustableDialog.close()
}
footer: StatusDialogFooter {
leftButtons: ObjectModel {
StatusRoundButton {
icon.name: "arrow-left"
onClicked: autoAdjustableDialogContent.implicitWidth -= 100
}
StatusRoundButton {
icon.name: "arrow-right"
onClicked: autoAdjustableDialogContent.implicitWidth += 100
}
}
rightButtons: ObjectModel {
StatusRoundButton {
icon.name: "arrow-down"
onClicked: autoAdjustableDialogContent.implicitHeight -= 100
}
StatusRoundButton {
icon.name: "arrow-up"
onClicked: autoAdjustableDialogContent.implicitHeight += 100
}
}
}
Rectangle {
id: autoAdjustableDialogContent
anchors.fill: parent
implicitWidth: 200
implicitHeight: 200
color: Theme.palette.primaryColor3
StatusBaseText {
anchors.centerIn: parent
text: "W: %1 H: %2\nIW: %3 IH: %4".arg(parent.width).arg(parent.height).arg(parent.implicitWidth).arg(parent.implicitHeight)
}
}
}
}
StatusButton {
text: "Complex dialog"
onClicked: complexDialog.open()
StatusDialog {
id: complexDialog
header: StatusDialogHeader {
id: dialogHeader
headline.title: "Complex dialog"
headline.subtitle: "identicon, title subtitle, custom actions"
leftComponent: StatusLetterIdenticon {
name: dialogHeader.headline.title
}
actions {
infoButton.visible: true
customButtons: ObjectModel {
StatusFlatRoundButton {
icon.name: "warning"
icon.width: 20
icon.height: 20
}
}
closeButton.onClicked: complexDialog.close()
}
}
footer: StatusDialogFooter {
leftButtons: ObjectModel {
StatusRoundButton {
icon.name: "arrow-left"
}
}
rightButtons: ObjectModel {
StatusButton {
text: "Custom cancel action"
type: StatusButton.Danger
}
StatusButton {
text: "Custom approve action"
}
}
}
ColumnLayout {
anchors.fill: parent
StatusBaseText {
text: "Content A"
}
StatusBaseText {
text: "Content B"
}
StatusBaseText {
text: "Content C"
}
}
}
}
StatusButton {
text: "Custom header/footer"
onClicked: customHeaderAndFooter.open()
StatusDialog {
id: customHeaderAndFooter
title: "No buttons"
header: Rectangle {
implicitHeight: customHeaderText.height * 2
implicitWidth: customHeaderText.width * 2
border.width: 2
color: Theme.palette.statusPopupMenu.hoverBackgroundColor
StatusBaseText {
id: customHeaderText
anchors.centerIn: parent
text: "Custom header"
}
}
footer: Rectangle {
implicitHeight: customHeaderText.height * 2
implicitWidth: customHeaderText.width * 2
border.width: 2
color: Theme.palette.statusPopupMenu.hoverBackgroundColor
StatusBaseText {
id: customFooter
anchors.centerIn: parent
text: "Custom footer"
}
}
StatusBaseText {
anchors.fill: parent
text: "Content"
}
}
}
}
@@ -26,7 +26,7 @@ Column {
anchors.horizontalCenter: parent.horizontalCenter
expandable: false
icon.name: "seed-phrase"
asset.name: "seed-phrase"
primaryText: "Back up seed phrase"
secondaryText: "Back up your seed phrase now to secure this account ajhaDH SDHSAHDLSADBSA,DLISAHDLASD ADASDHASLDHALSDHAS DAS,DASJDGLIASGD"
button.text: qsTr("Back up seed phrase")
@@ -36,7 +36,7 @@ Column {
anchors.horizontalCenter: parent.horizontalCenter
expandable: true
icon.name: "secret"
asset.name: "secret"
primaryText: "Account signing phrase"
secondaryText: "View your signing phrase and ensure that you never get scammed. View your signing phrase and ensure that you never get scammed."
expandableComponent: notImplemented
@@ -46,7 +46,7 @@ Column {
anchors.horizontalCenter: parent.horizontalCenter
expandable: true
icon.name: "seed-phrase"
asset.name: "seed-phrase"
primaryText: "View private key"
secondaryText: "Back up your seed phrase now to secure this account"
expandableComponent: notImplemented
@@ -74,7 +74,8 @@ Column {
type: StatusExpandableItem.Type.Secondary
expandable: true
image.source: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
asset.isImage: true
asset.name: "qrc:/demoapp/data/profile-image-1.jpeg"
primaryText: "CryptoKitties"
additionalText: "1456 USD"
expandableComponent: notImplemented
@@ -85,7 +86,8 @@ Column {
type: StatusExpandableItem.Type.Secondary
expandable: true
image.source: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
asset.isImage: true
asset.name: "qrc:/demoapp/data/profile-image-1.jpeg"
primaryText: "Adding Really long text to test scenario of having very long text along with tertiary text"
additionalText: "564.90 USD"
expandableComponent: notImplemented
+188 -23
View File
@@ -1,11 +1,20 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import QtQuick.Dialogs 1.3
import QtQml 2.14
import StatusQ.Controls 0.1
import StatusQ.Components 0.1
import QtGraphicalEffects 1.14
import StatusQ.Components 0.1
import StatusQ.Controls 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Popups 0.1
Item {
id: root
@@ -15,6 +24,12 @@ Item {
property var testControls: [ctrl1, ctrl2, ctrl3]
property bool globalStylePreferRound: true
property var testImageList: ["qrc:/demoapp/data/logo-test-image.png",
"qrc:/demoapp/data/profile-image-2.jpeg",
"qrc:/demoapp/data/profile-image-1.jpeg"]
property int testImageIndex: 0
property int testSpacing: 0
property int testFrameMargins: 10
ColumnLayout {
id: mainLayout
@@ -22,7 +37,12 @@ Item {
anchors.fill: parent
RowLayout {
spacing: root.testSpacing
ColumnLayout {
spacing: root.testSpacing
Layout.margins: root.testSpacing
Text {
text: `AR: ${ctrl1.aspectRatio.toFixed(2)}`
}
@@ -32,8 +52,9 @@ Item {
Layout.fillWidth: true
Layout.fillHeight: true
source: "qrc:/demoapp/data/logo-test-image.png"
source: root.testImageList[root.testImageIndex]
windowStyle: globalStylePreferRound ? StatusImageCrop.WindowStyle.Rounded : StatusImageCrop.WindowStyle.Rectangular
margins: root.testFrameMargins
}
Text {
text: `AR: ${ctrl2.aspectRatio.toFixed(2)}`
@@ -43,13 +64,15 @@ Item {
Layout.fillWidth: true
Layout.fillHeight: true
source: "qrc:/demoapp/data/logo-test-image.png"
source: root.testImageList[root.testImageIndex]
windowStyle: globalStylePreferRound ? StatusImageCrop.WindowStyle.Rectangular : StatusImageCrop.WindowStyle.Rounded
aspectRatio: 16/9
enableCheckers: true
margins: root.testFrameMargins + 2
}
}
ColumnLayout {
Layout.margins: root.testSpacing
Text {
text: `AR: ${ctrl3.aspectRatio.toFixed(2)}`
}
@@ -59,36 +82,178 @@ Item {
Layout.fillWidth: true
Layout.fillHeight: true
source: "qrc:/demoapp/data/logo-test-image.png"
source: root.testImageList[root.testImageIndex]
windowStyle: globalStylePreferRound ? StatusImageCrop.WindowStyle.Rounded : StatusImageCrop.WindowStyle.Rectangular
aspectRatio: 0.8
margins: root.testFrameMargins + 5.3
}
}
}
Shortcut {
sequence: StandardKey.ZoomIn
onActivated: {
for(let i in testControls) {
const c = testControls[i]
c.setCropRect(ctrl1.inflateRectBy(c.cropRect, -0.05))
RowLayout {
StatusButton {
text: qsTr("Cycle image")
onClicked: {
let newIndex = root.testImageIndex
newIndex++
if(newIndex >= root.testImageList.length)
newIndex = 0
root.testImageIndex = newIndex
}
}
}
Shortcut {
sequence: StandardKey.ZoomOut
onActivated: {
for(let i in testControls) {
const c = testControls[i]
c.setCropRect(ctrl1.inflateRectBy(c.cropRect, 0.05))
StatusButton {
text: qsTr("Cycle spacing")
onClicked: {
root.testSpacing += (root.testSpacing/2) + 1
if(root.testSpacing > 35)
root.testSpacing = 0
}
}
}
Shortcut {
sequences: ["Ctrl+W"]
onActivated: globalStylePreferRound = !globalStylePreferRound
StatusButton {
text: qsTr("Cycle frame margins")
onClicked: {
root.testFrameMargins += (root.testFrameMargins/2) + 1
if(root.testFrameMargins > 50)
root.testFrameMargins = 0
}
}
StatusButton {
text: qsTr("Load external image")
onClicked: workflowLoader.active = true
}
}
}
Loader {
id: workflowLoader
sourceComponent: workflowComponent
active: false
onStatusChanged: {
if(status === Loader.Ready) {
item.imageFileDialogTitle = qsTr("Test Title")
item.title = "Test popup"
item.acceptButtonText = "Load Custom Image"
item.chooseImageToCrop()
}
}
Connections {
target: workflowLoader.item
function onImageCropped(image, cropRect) {
ctrl1.source = image
ctrl2.source = image
ctrl3.source = image
}
function onCanceled() {
workflowLoader.active = false
}
}
}
Component {
id: workflowComponent
Item {
id: workflowItem
property alias aspectRatio: imageCropper.aspectRatio
property alias windowStyle: imageCropper.windowStyle
/*required*/ property string imageFileDialogTitle: ""
/*required*/ property string title: ""
/*required*/ property string acceptButtonText: ""
property bool roundedImage: true
signal imageCropped(var image, var cropRect)
signal canceled()
function chooseImageToCrop() {
fileDialog.open()
}
FileDialog {
id: fileDialog
title: workflowItem.imageFileDialogTitle
folder: workflowItem.userSelectedImage ? imageCropper.source.substr(0, imageCropper.source.lastIndexOf("/")) : shortcuts.pictures
nameFilters: [qsTr("Supported image formats (%1)").arg("*.jpg *.jpeg *.jfif *.webp *.png *.heif")]
onAccepted: {
if (fileDialog.fileUrls.length > 0) {
imageCropper.source = fileDialog.fileUrls[0]
imageCropperModal.open()
}
}
onRejected: workflowItem.canceled()
} // FileDialog
StatusModal {
id: imageCropperModal
header.title: workflowItem.title
anchors.centerIn: Overlay.overlay
width: workflowItem.roundedImage ? 480 : 580
onClosed: workflowItem.canceled()
StatusImageCropPanel {
id: imageCropper
implicitHeight: workflowItem.roundedImage ? 350 : 370
anchors {
fill: parent
leftMargin: 10 * 2
rightMargin: 10 * 2
topMargin: 15
bottomMargin: 15
}
margins: workflowItem.roundedImage ? 10 : 20
windowStyle: workflowItem.roundedImage ? StatusImageCrop.WindowStyle.Rounded : StatusImageCrop.WindowStyle.Rectangular
enableCheckers: true
}
rightButtons: [
StatusButton {
text: workflowItem.acceptButtonText
enabled: imageCropper.sourceSize.width > 0 && imageCropper.sourceSize.height > 0
onClicked: {
workflowItem.imageCropped(imageCropper.source, imageCropper.cropRect)
imageCropperModal.close()
}
}
]
} // StatusModal
} // Item
}
Shortcut {
sequence: StandardKey.ZoomIn
onActivated: {
for(let i in testControls) {
const c = testControls[i]
c.setCropRect(ctrl1.inflateRectBy(c.cropRect, -0.05))
}
}
}
Shortcut {
sequence: StandardKey.ZoomOut
onActivated: {
for(let i in testControls) {
const c = testControls[i]
c.setCropRect(ctrl1.inflateRectBy(c.cropRect, 0.05))
}
}
}
Shortcut {
sequences: ["Ctrl+W"]
onActivated: globalStylePreferRound = !globalStylePreferRound
}
}
+55 -30
View File
@@ -12,51 +12,59 @@ Column {
spacing: 8
StatusInput {
input.placeholderText: "Placeholder"
placeholderText: "Placeholder"
}
StatusInput {
label: "Label"
input.placeholderText: "Disabled"
placeholderText: "Disabled"
input.enabled: false
}
StatusInput {
input.placeholderText: "Clearable"
placeholderText: "Clearable"
input.clearable: true
}
StatusInput {
input.placeholderText: "Invalid"
placeholderText: "Invalid"
input.valid: false
}
StatusInput {
label: "Label"
input.icon.name: "search"
input.asset.name: "search"
input.placeholderText: "Input with icon"
}
StatusInput {
label: "Label"
input.placeholderText: "Placeholder"
placeholderText: "Placeholder"
input.clearable: true
}
StatusInput {
charLimit: 30
input.placeholderText: "Placeholder"
placeholderText: "Placeholder"
input.clearable: true
}
StatusInput {
label: "Label"
charLimit: 30
input.placeholderText: "Placeholder"
placeholderText: "Placeholder"
input.clearable: true
}
StatusPasswordInput {
placeholderText: "Password"
}
StatusPasswordInput {
signingPhrase: "orange hello cygnet"
placeholderText: "Password"
}
Item {
implicitWidth: 480
implicitHeight: 82
@@ -69,19 +77,34 @@ Column {
textEdit.input.anchors.leftMargin: 16
textEdit.input.anchors.rightMargin: 16
textEdit.input.anchors.topMargin: 11
textEdit.label: "Input with drop down selection list"
textEdit.label: "Input with drop down selection list" + (insertedWord ? ` (${insertedWord})` : "")
leftComponentText: "1"
inputList: ListModel {
ListElement {
seedWord: "add"
}
ListElement {
seedWord: "address"
}
ListElement {
seedWord: "panda"
}
ListElement {
seedWord: "posible"
}
ListElement {
seedWord: "win"
}
ListElement {
seedWord: "wine"
}
ListElement {
seedWord: "wing"
}
}
property string insertedWord: ""
onDoneInsertingWord: insertedWord = word
}
}
@@ -91,30 +114,31 @@ Column {
errorMessage: "Error message"
input.clearable: true
input.valid: false
input.placeholderText: "Placeholder"
placeholderText: "Placeholder"
}
StatusInput {
label: "StatusInput"
secondaryLabel: "with right icon"
input.icon.width: 15
input.icon.height: 11
input.icon.name: text !== "" ? "checkmark" : ""
input.asset.width: 15
input.asset.height: 11
input.asset.name: text !== "" ? "checkmark" : ""
input.leftIcon: false
}
StatusInput {
label: "Label"
secondaryLabel: "secondary label"
input.placeholderText: "Placeholder"
input.implicitHeight: 56
placeholderText: "Placeholder"
minimumHeight: 56
maximumHeight: 56
}
StatusInput {
id: input
label: "Label"
charLimit: 30
input.placeholderText: "Input with validator"
placeholderText: "Input with validator"
validators: [
StatusMinLengthValidator {
@@ -132,7 +156,7 @@ Column {
StatusInput {
label: "Input with <i>StatusRegularExpressionValidator</i>"
charLimit: 30
input.placeholderText: `Must match regex(${validators[0].regularExpression.toString()}) and <= 30 chars`
placeholderText: `Must match regex(${validators[0].regularExpression.toString()}) and <= 30 chars`
validationMode: StatusInput.ValidationMode.IgnoreInvalidInput
validators: [
@@ -145,7 +169,7 @@ Column {
StatusInput {
label: "Label"
input.placeholderText: "Input width component (right side)"
placeholderText: "Input width component (right side)"
input.rightComponent: StatusIcon {
icon: "cancel"
height: 16
@@ -156,28 +180,29 @@ Column {
StatusInput {
input.multiline: true
input.placeholderText: "Multiline"
placeholderText: "Multiline"
}
StatusInput {
input.multiline: true
input.placeholderText: "Multiline with static height"
input.implicitHeight: 100
placeholderText: "Multiline with static height"
minimumHeight: 100
maximumHeight: 100
}
StatusInput {
input.multiline: true
input.placeholderText: "Multiline with max/min"
input.minimumHeight: 80
input.maximumHeight: 200
placeholderText: "Multiline with max/min"
minimumHeight: 80
maximumHeight: 200
}
StatusInput {
property bool toggled: true
label: "Input with emoji icon"
input.placeholderText: "Enter Name"
input.icon.emoji: toggled ? "😁" : "🧸"
input.icon.color: "blue"
input.asset.emoji: toggled ? "😁" : "🧸"
input.asset.color: "blue"
input.isIconSelectable: true
onIconClicked: {
toggled = !toggled
@@ -188,9 +213,9 @@ Column {
property bool toggled: true
label: "Input with selectable icon which is not an emoji"
input.placeholderText: "Enter Name"
input.icon.emoji: ""
input.icon.name: toggled ? "filled-account" : "image"
input.icon.color: "blue"
input.asset.emoji: ""
input.asset.name: toggled ? "filled-account" : "image"
input.asset.color: "blue"
input.isIconSelectable: true
onIconClicked: {
toggled = !toggled
+63
View File
@@ -0,0 +1,63 @@
import QtQuick 2.14
import QtQuick.Layouts 1.14
import StatusQ.Components 0.1
import StatusQ.Controls 0.1
import StatusQ.Core.Utils 0.1
ColumnLayout {
spacing: 20
StatusItemSelector {
id: selector
icon: "qrc:/images/SNT.png"
iconSize: 24
title: "Item Selector Title"
defaultItemText: "Example: Empty items"
andOperatorText: "and"
orOperatorText: "or"
itemsModel: ListModel {
id: model
}
StatusDropdown {
id: dropdown
parent: selector.addButton
width: 200
contentItem: ColumnLayout {
spacing: 10
StatusInput {
id: input
text: "Sample"
Layout.fillWidth: true
}
StatusButton {
Layout.alignment: Qt.AlignHCenter
text: "Add element"
onClicked: {
model.append({
text: input.text,
imageSource: "qrc:/images/SNT.png",
operator: model.count > 0 ? Utils.Operators.Or : Utils.Operators.None
})
dropdown.close()
}
}
}
}
addButton.onClicked: {
dropdown.x = mouse.x
dropdown.y = mouse.y
dropdown.open()
}
}
StatusButton {
Layout.alignment: Qt.AlignHCenter
text: "Clear list"
onClicked: { selector.itemsModel.clear() }
}
}
+2 -1
View File
@@ -34,6 +34,7 @@ GridLayout {
inputList: Models.languageNoImagePickerModel
placeholderSearchText: qsTr("Search Languages")
menuAlignment: StatusListPicker.MenuAlignment.Center
multiSelection: true
}
StatusListPicker {
@@ -60,7 +61,7 @@ GridLayout {
width: 500
text: "4 different configurations for the `StatusListPicker` component:\n
* Single selection. \n
* Single selection but dynamically changed to multiple selection (model provides multiple selected items).\n
* Multiple selection without images.\n
* Multiple selection.\n
* Multiple selection and displayed name is the symbol + shortName\n"
color: Theme.palette.baseColor1
+42 -17
View File
@@ -28,6 +28,11 @@ GridLayout {
onClicked: customMenu.popup()
}
StatusButton {
text: "Menu with custom font settings"
onClicked: differentFontMenu.popup()
}
StatusPopupMenu {
id: simpleMenu
@@ -50,30 +55,30 @@ GridLayout {
StatusMenuItem {
text: "One"
iconSettings.name: "info"
assetSettings.name: "info"
}
StatusMenuSeparator {}
StatusMenuItem {
text: "Two"
iconSettings.name: "info"
assetSettings.name: "info"
}
StatusMenuItem {
text: "Three"
iconSettings.name: "info"
assetSettings.name: "info"
}
StatusPopupMenu {
title: "Four"
StatusMenuItem {
text: "One"
iconSettings.name: "info"
assetSettings.name: "info"
}
StatusMenuItem {
text: "Three"
iconSettings.name: "info"
assetSettings.name: "info"
}
}
}
@@ -84,7 +89,7 @@ GridLayout {
subMenuItemIcons: [
{ icon: "chat" },
{
source: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
source: "qrc:/demoapp/data/profile-image-1.jpeg"
},
{
isLetterIdenticon: true,
@@ -103,14 +108,16 @@ GridLayout {
StatusMenuItem {
text: "vitalik.eth"
image.source: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0Bh
assetSettings.isImage: true
assetSettings.name: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0Bh
CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
image.isIdenticon: true
assetSettings.imgIsIdenticon: true
}
StatusMenuItem {
text: "Pascal"
image.source: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
assetSettings.isImage: true
assetSettings.name: "qrc:/demoapp/data/profile-image-1.jpeg"
}
}
@@ -119,21 +126,21 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
StatusMenuItem {
text: "welcome"
iconSettings.name: "channel"
iconSettings.color: Theme.palette.directColor1
assetSettings.name: "channel"
assetSettings.color: Theme.palette.directColor1
}
StatusMenuItem {
text: "support"
iconSettings.name: "channel"
iconSettings.color: Theme.palette.directColor1
assetSettings.name: "channel"
assetSettings.color: Theme.palette.directColor1
}
StatusMenuHeadline { text: "Public" }
StatusMenuItem {
text: "news"
iconSettings.name: "channel"
iconSettings.color: Theme.palette.directColor1
assetSettings.name: "channel"
assetSettings.color: Theme.palette.directColor1
}
}
@@ -142,9 +149,27 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I
StatusMenuItem {
text: "welcome"
iconSettings.isLetterIdenticon: true
iconSettings.background.color: "red"
assetSettings.isLetterIdenticon: true
assetSettings.bgColor: "red"
}
}
}
StatusPopupMenu {
id: differentFontMenu
StatusMenuItem {
text: "Bold"
fontSettings.bold: true
}
StatusMenuItem {
text: "Italic"
fontSettings.italic: true
}
StatusMenuItem {
text: "16px"
fontSettings.pixelSize: 16
}
}
}
+29 -16
View File
@@ -8,36 +8,49 @@ import StatusQ.Controls 0.1
import StatusQ.Popups 0.1
import Sandbox 0.1
Column {
spacing: 8
spacing: 20
ListModel {
id: commmonModel
ListElement {
name: "Pascal"
}
ListElement {
name: "Khushboo"
}
ListElement {
name: "Alexandra"
}
ListElement {
name: "Eric"
}
}
StatusBaseText {
font.pixelSize: 16
color: Theme.palette.dangerColor1
text: "This component should no longer be used.<br />Please, use `StatusComboBox` instead."
textFormat: Text.MarkdownText
}
StatusSelect {
id: select
label: "Some label"
model: ListModel {
ListElement {
name: "Pascal"
}
ListElement {
name: "Khushboo"
}
ListElement {
name: "Alexandra"
}
ListElement {
name: "Eric"
}
}
model: commmonModel
selectMenu.delegate: StatusMenuItemDelegate {
statusPopupMenu: select
action: StatusMenuItem {
iconSettings.name: "filled-account"
assetSettings.name: "filled-account"
text: name
onTriggered: {
selectedItem.text = name
}
}
}
selectedItemComponent: Item {
id: selectedItem
anchors.fill: parent
+1 -1
View File
@@ -19,7 +19,7 @@ Item {
ListElement {
publicId: "0x1"
name: "vitalikbuterin"
icon: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
icon: "qrc:/demoapp/data/profile-image-1.jpeg"
isIdenticon: false
onlineStatus: 1
isReadonly: false
+61
View File
@@ -0,0 +1,61 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
Column {
id: root
spacing: 8
Component.onCompleted: {
focusedTextArea.forceActiveFocus()
}
StatusTextArea {
id: focusedTextArea
width: parent.width
placeholderText: "Initially focused text area"
KeyNavigation.tab: unfocusedTextArea
}
StatusTextArea {
id: unfocusedTextArea
width: parent.width
placeholderText: "Unfocused text area (hover me to see the color change)"
KeyNavigation.tab: invalidTextArea
}
StatusTextArea {
id: invalidTextArea
width: parent.width
valid: false
placeholderText: "Invalid text area, should display red border"
KeyNavigation.tab: longTextArea
}
StatusScrollView {
padding: 0 // use our own (StatusTextArea) padding
width: parent.width
height: 120
TextArea.flickable: longTextArea
StatusTextArea {
id: longTextArea
text: "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Integer imperdiet lectus quis justo. Sed vel lectus. \
Donec odio tempus molestie, porttitor ut, iaculis quis, sem. Morbi scelerisque luctus velit. Nunc auctor. Nullam at \
arcu a est sollicitudin euismod. Cras elementum. Class aptent taciti sociosqu ad litora torquent per conubia nostra, \
per inceptos hymenaeos. Fusce aliquam vestibulum ipsum. Etiam sapien elit, consequat eget, tristique non, venenatis quis, ante. \
Nullam sit amet magna in magna gravida vehicula. Cras pede libero, dapibus nec, pretium sit amet, tempor quis. Nullam faucibus \
mi quis velit. Nam sed tellus id magna elementum tincidunt. Duis bibendum, lectus ut viverra rhoncus, dolor nunc faucibus libero, \
eget facilisis enim ipsum id lacus. Maecenas aliquet accumsan leo. Aliquam erat volutpat."
KeyNavigation.tab: focusedTextArea
}
}
StatusTextArea {
enabled: false
placeholderText: "Disabled text area"
}
}
+3
View File
@@ -35,6 +35,9 @@ Item {
onClose: {
console.warn("toast closed: ", modelData.title)
}
onClicked: {
console.warn("toast clicked")
}
}
}
}
+51 -41
View File
@@ -1,22 +1,5 @@
<RCC>
<qresource prefix="/">
<file>main.qml</file>
<file>pages/StatusAccountSelectorPage.qml</file>
<file>pages/StatusAddressPage.qml</file>
<file>pages/StatusAssetSelectorPage.qml</file>
<file>pages/StatusChatCommandButtonPage.qml</file>
<file>pages/StatusChatInfoToolBarPage.qml</file>
<file>pages/StatusColorSelectorPage.qml</file>
<file>pages/StatusExpandableSettingsItemPage.qml</file>
<file>pages/StatusInputPage.qml</file>
<file>pages/StatusMacNotificationPage.qml</file>
<file>pages/StatusPopupMenuPage.qml</file>
<file>pages/StatusSelectPage.qml</file>
<file>pages/StatusTabBarIconButtonPage.qml</file>
<file>pages/StatusTabSwitchPage.qml</file>
<file>pages/StatusWalletColorButtonPage.qml</file>
<file>pages/StatusWalletColorSelectPage.qml</file>
<file>pages/StatusPasswordStrengthIndicatorPage.qml</file>
<file>controls/Buttons.qml</file>
<file>controls/Controls.qml</file>
<file>controls/Icons.qml</file>
@@ -24,49 +7,76 @@
<file>controls/ListItems.qml</file>
<file>controls/Others.qml</file>
<file>controls/Popups.qml</file>
<file>demoapp/data/logo-test-image.png</file>
<file>demoapp/data/Models.qml</file>
<file>demoapp/data/qmldir</file>
<file>demoapp/ChatChannelView.qml</file>
<file>demoapp/CreateChatView.qml</file>
<file>demoapp/DemoCommunityDetailModal.qml</file>
<file>demoapp/DemoContactRequestsModal.qml</file>
<file>demoapp/StatusAppChatView.qml</file>
<file>demoapp/StatusAppCommunitiesPortalView.qml</file>
<file>demoapp/StatusAppCommunityView.qml</file>
<file>demoapp/StatusAppProfileSettingsView.qml</file>
<file>demoapp/data/Models.qml</file>
<file>demoapp/data/qmldir</file>
<file>demoapp/data/logo-test-image.png</file>
<file>DemoApp.qml</file>
<file>ThemeSwitch.qml</file>
<file>pages/StatusColorSelectorGridPage.qml</file>
<file>pages/StatusListPickerPage.qml</file>
<file>pages/StatusPinInputPage.qml</file>
<file>pages/StatusTagSelectorPage.qml</file>
<file>pages/StatusToastMessagePage.qml</file>
<file>pages/StatusWizardStepperPage.qml</file>
<file>pages/StatusTabBarButtonPage.qml</file>
<file>pages/StatusColorSpacePage.qml</file>
<file>images/Coinbase.png</file>
<file>images/CoinBaseCommunityBanner.png</file>
<file>images/CommunityBanner1.png</file>
<file>images/CryptoKitties.png</file>
<file>images/CryptoPunks.png</file>
<file>images/Dragonerum.png</file>
<file>images/FriendsBenefits.png</file>
<file>images/logo-test-image.png</file>
<file>images/P2PCrypto.png</file>
<file>images/SNT.png</file>
<file>images/Socks.png</file>
<file>images/StatusPunks.png</file>
<file>images/CommunityBanner1.png</file>
<file>images/Coinbase.png</file>
<file>images/CoinBaseCommunityBanner.png</file>
<file>images/DribbbleCommunityBanner.png</file>
<file>images/Ethereum.png</file>
<file>images/EthereumCommunityBanner.png</file>
<file>images/Fluff.png</file>
<file>images/FriendsBenefits.png</file>
<file>images/logo-test-image.png</file>
<file>images/P2PCrypto.png</file>
<file>images/RARI.png</file>
<file>images/Rarible.png</file>
<file>images/RaribleCommunityBanner.png</file>
<file>images/SNT.png</file>
<file>images/Socks.png</file>
<file>images/Spotify.png</file>
<file>images/SpotifyCommunityBanner.png</file>
<file>images/SR.png</file>
<file>images/SuperRareCommunityBanner.png</file>
<file>images/RARI.png</file>
<file>images/SRToken.png</file>
<file>images/StatusPunks.png</file>
<file>images/SuperRareCommunityBanner.png</file>
<file>pages/StatusAccountSelectorPage.qml</file>
<file>pages/StatusAddressPage.qml</file>
<file>pages/StatusCardPage.qml</file>
<file>pages/StatusChatCommandButtonPage.qml</file>
<file>pages/StatusChatInfoToolBarPage.qml</file>
<file>pages/StatusColorSelectorGridPage.qml</file>
<file>pages/StatusColorSelectorPage.qml</file>
<file>pages/StatusColorSpacePage.qml</file>
<file>pages/StatusCommunityCardPage.qml</file>
<file>pages/StatusCommunityTagsPage.qml</file>
<file>pages/StatusDialogPage.qml</file>
<file>pages/StatusExpandableSettingsItemPage.qml</file>
<file>pages/StatusImageCropPanelPage.qml</file>
<file>pages/StatusInputPage.qml</file>
<file>pages/StatusItemSelectorPage.qml</file>
<file>pages/StatusListPickerPage.qml</file>
<file>pages/StatusMacNotificationPage.qml</file>
<file>pages/StatusPasswordStrengthIndicatorPage.qml</file>
<file>pages/StatusPinInputPage.qml</file>
<file>pages/StatusPopupMenuPage.qml</file>
<file>pages/StatusSelectPage.qml</file>
<file>pages/StatusTabBarButtonPage.qml</file>
<file>pages/StatusTabBarIconButtonPage.qml</file>
<file>pages/StatusTabSwitchPage.qml</file>
<file>pages/StatusTagSelectorPage.qml</file>
<file>pages/StatusToastMessagePage.qml</file>
<file>pages/StatusWalletColorButtonPage.qml</file>
<file>pages/StatusWalletColorSelectPage.qml</file>
<file>pages/StatusWizardStepperPage.qml</file>
<file>DemoApp.qml</file>
<file>main.qml</file>
<file>ThemeSwitch.qml</file>
<file>examples/FilteringSorting.qml</file>
<file>demoapp/data/profile-image-1.jpeg</file>
<file>demoapp/data/profile-image-2.jpeg</file>
<file>pages/StatusComboBoxPage.qml</file>
</qresource>
</RCC>
-96
View File
@@ -1,96 +0,0 @@
QT += quick svg
CONFIG += c++11 warn_on qtquickcompiler
QML_IMPORT_PATH= $$PWD/../src
DEFINES += QT_DEPRECATED_WARNINGS
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
handler.cpp \
main.cpp \
sandboxapp.cpp \
spellchecker.cpp \
!macx {
SOURCES += statuswindow.cpp
}
TARGET = sandboxapp
DESTDIR = $$PWD/bin
DESTDIR = $$PWD/bin
macx {
CONFIG -= app_bundle
OBJECTIVE_SOURCES += \
statuswindow_mac.mm
hunspellTarget.depends = FORCE
hunspellTarget.commands = brew install hunspell
QMAKE_EXTRA_TARGETS += hunspellTarget
exists (/usr/local/lib/libhunspell-1.7.a) {
LIBS += -L"/usr/local/lib" -lhunspell-1.7
INCLUDEPATH += /usr/local/include/hunspell
DEFINES += USE_HUNSPELL
message("hunspell exists in /usr/local/lib")
}
copydata.commands = $(COPY_DIR) $$PWD/dictionaries $$DESTDIR
first.depends = $(first) copydata
export(first.depends)
export(copydata.commands)
QMAKE_EXTRA_TARGETS += first copydata
}
ios {
LIBS += -framework UIKit
QMAKE_TARGET_BUNDLE_PREFIX = "im.status"
#QMAKE_XCODE_CODE_SIGN_IDENTITY = "iPhone Developer"
MY_DEVELOPMENT_TEAM.name = "STATUS HOLDINGS PTE.LTD"
MY_DEVELOPMENT_TEAM.value = "DTX7Z4U3YA"
QMAKE_MAC_XCODE_SETTINGS += MY_DEVELOPMENT_TEAM
}
RESOURCES += qml.qrc \
$$PWD/../statusq.qrc
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
#OTHER_FILES += $$files($$PWD/../src/*, true)
HEADERS += \
handler.h \
sandboxapp.h \
statuswindow.h \
spellchecker.h
OTHER_FILES += $$files($$PWD/../*.qml, true)
OTHER_FILES += $$files($$PWD/*.qml, true)
android {
DISTFILES += \
android/AndroidManifest.xml \
android/build.gradle \
android/gradle/wrapper/gradle-wrapper.jar \
android/gradle/wrapper/gradle-wrapper.properties \
android/gradlew \
android/gradlew.bat \
android/res/values/libs.xml
contains(ANDROID_TARGET_ARCH,armeabi-v7a) {
ANDROID_PACKAGE_SOURCE_DIR = \
$$PWD/android
}
}
+20 -10
View File
@@ -3,15 +3,20 @@
#include <QQmlContext>
#include <QWindow>
#include <QDebug>
#include <QDirIterator>
#include "statuswindow.h"
#include "spellchecker.h"
SandboxApp::SandboxApp(int &argc, char **argv)
: QGuiApplication(argc, argv),
m_handler(new Handler(this))
: QGuiApplication(argc, argv)
{
connect(m_handler, &Handler::restartQml, this, &SandboxApp::restartEngine, Qt::QueuedConnection);
#ifdef QT_DEBUG
connect(&m_watcher, &QFileSystemWatcher::directoryChanged, [this](const QString&) {
restartEngine();
});
#endif
}
void SandboxApp::startEngine()
@@ -20,18 +25,23 @@ void SandboxApp::startEngine()
qmlRegisterType<SpellChecker>("Sandbox", 0, 1, "Spellchecker");
#ifdef QT_DEBUG
const QUrl url = QUrl::fromLocalFile(applicationDirPath() + "/../main.qml");
const QUrl url = QUrl::fromLocalFile(SRC_DIR + QStringLiteral("/main.qml"));
m_watcher.addPath(applicationDirPath() + "/../");
QDirIterator it(applicationDirPath() + "/../", QDir::Dirs | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
while (it.hasNext()) {
if (!it.filePath().isEmpty()) {
m_watcher.addPath(it.filePath());
}
it.next();
}
#else
const QUrl url(QStringLiteral("qrc:/main.qml"));
#endif
m_engine.rootContext()->setContextProperty("app", m_handler);
#ifdef QT_DEBUG
m_engine.addImportPath(applicationDirPath() + "/../../src");
m_engine.addImportPath(SRC_DIR + QStringLiteral("/../src"));
#else
m_engine.addImportPath(QStringLiteral("qrc:/src"));
m_engine.addImportPath(QStringLiteral(":/"));
#endif
qDebug() << m_engine.importPathList();
QObject::connect(&m_engine, &QQmlApplicationEngine::objectCreated,
@@ -44,7 +54,7 @@ void SandboxApp::startEngine()
void SandboxApp::restartEngine()
{
const QUrl url(applicationDirPath() + "/../main.qml");
const QUrl url = QUrl::fromLocalFile(SRC_DIR + QStringLiteral("/main.qml"));
QWindow *rootWindow = qobject_cast<QWindow*>(m_engine.rootObjects().at(0));
if (rootWindow) {
rootWindow->close();
+7 -2
View File
@@ -4,7 +4,9 @@
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "handler.h"
#ifdef QT_DEBUG
#include <QFileSystemWatcher>
#endif
class SandboxApp : public QGuiApplication
{
@@ -18,7 +20,10 @@ public slots:
private:
QQmlApplicationEngine m_engine;
Handler *m_handler;
#ifdef QT_DEBUG
QFileSystemWatcher m_watcher;
#endif
};
#endif // SANDBOXAPP_H
+2 -8
View File
@@ -1,10 +1,4 @@
#!/bin/bash
make clean
if [[ $OSTYPE == 'darwin'* ]]
then
qmake sandbox.pro -spec macx-clang CONFIG+=debug CONFIG+=x86_64 && /usr/bin/make qmake_all
else
qmake sandbox.pro CONFIG+=debug CONFIG+=x86_64 && /usr/bin/make qmake_all
fi
make
cmake -B build
cmake --build build
+3 -3
View File
@@ -9,7 +9,7 @@
#include <QLocale>
#include <QRegularExpression>
#include <QApplication>
#include <QGuiApplication>
#include <QDir>
SpellChecker::SpellChecker(QObject *parent)
@@ -53,8 +53,8 @@ void SpellChecker::initHunspell()
delete m_hunspell;
}
QString dictFile = QApplication::applicationDirPath() + "/dictionaries/" + m_lang + "/index.dic";
QString affixFile = QApplication::applicationDirPath() + "/dictionaries/" + m_lang + "/index.aff";
QString dictFile = QGuiApplication::applicationDirPath() + "/dictionaries/" + m_lang + "/index.dic";
QString affixFile = QGuiApplication::applicationDirPath() + "/dictionaries/" + m_lang + "/index.aff";
QByteArray dictFilePathBA = dictFile.toLocal8Bit();
QByteArray affixFilePathBA = affixFile.toLocal8Bit();
m_hunspell = new Hunspell(affixFilePathBA.constData(),
+46 -2
View File
@@ -1,5 +1,33 @@
#include "statuswindow.h"
StatusWindow::StatusWindow(QQuickWindow *parent)
: QQuickWindow(parent)
, m_isFullScreen(false)
{
removeTitleBar();
connect(this, &QQuickWindow::windowStateChanged, [&](Qt::WindowState windowState) {
if (windowState == Qt::WindowNoState) {
removeTitleBar();
m_isFullScreen = false;
emit isFullScreenChanged();
} else if (windowState == Qt::WindowFullScreen) {
m_isFullScreen = true;
emit isFullScreenChanged();
showTitleBar();
}
});
}
void StatusWindow::updatePosition()
{
auto point = QPoint(screen()->geometry().center().x() - geometry().width() / 2,
screen()->geometry().center().y() - geometry().height() / 2);
if (point != this->position()) {
this->setPosition(point);
}
}
void StatusWindow::toggleFullScreen()
{
if (m_isFullScreen) {
@@ -16,10 +44,26 @@ bool StatusWindow::isFullScreen() const
void StatusWindow::removeTitleBar()
{
#ifdef Q_OS_WIN
removeTitleBarWin();
#elif defined Q_OS_MACOS
removeTitleBarMac();
#endif
}
void StatusWindow::showTitleBar()
{
#ifdef Q_OS_WIN
showTitleBarWin();
#elif defined Q_OS_MACOS
showTitleBarMac();
#endif
}
#ifdef Q_OS_WIN
void StatusWindow::removeTitleBarWin()
{}
void StatusWindow::showTitleBarWin()
{}
#endif
+9 -33
View File
@@ -11,40 +11,11 @@ class StatusWindow: public QQuickWindow
Q_PROPERTY(bool isFullScreen READ isFullScreen NOTIFY isFullScreenChanged)
public:
struct EventCallbacks {
std::function<void()> onResize;
std::function<void()> willExitFullScreen;
std::function<void()> didExitFullScreen;
};
explicit StatusWindow(QWindow *parent = nullptr)
: QQuickWindow(parent),
m_isFullScreen(false)
{
removeTitleBar();
connect(this, &QQuickWindow::windowStateChanged, [&](Qt::WindowState windowState) {
if (windowState == Qt::WindowNoState) {
removeTitleBar();
m_isFullScreen = false;
emit isFullScreenChanged();
} else if (windowState == Qt::WindowFullScreen) {
m_isFullScreen = true;
emit isFullScreenChanged();
showTitleBar();
}
});
}
explicit StatusWindow(QQuickWindow *parent = nullptr);
Q_INVOKABLE void toggleFullScreen();
Q_INVOKABLE void updatePosition() {
auto point = QPoint(screen()->geometry().center().x() - geometry().width() / 2, screen()->geometry().center().y() - geometry().height() / 2);
if (point != this->position()) {
this->setPosition(point);
}
}
Q_INVOKABLE void updatePosition();
bool isFullScreen() const;
@@ -54,10 +25,15 @@ signals:
private:
void removeTitleBar();
void showTitleBar();
void initCallbacks();
#ifdef Q_OS_WIN
void removeTitleBarWin();
void showTitleBarWin();
#elif defined Q_OS_MACOS
void removeTitleBarMac();
void showTitleBarMac();
#endif
private:
EventCallbacks m_callbacks;
bool m_isFullScreen;
};
+2 -16
View File
@@ -12,21 +12,7 @@
#include <AppKit/NSButton.h>
#include <AppKit/AppKit.h>
void StatusWindow::toggleFullScreen()
{
if (m_isFullScreen) {
showNormal();
} else {
showFullScreen();
}
}
bool StatusWindow::isFullScreen() const
{
return m_isFullScreen;
}
void StatusWindow::removeTitleBar()
void StatusWindow::removeTitleBarMac()
{
NSView *nsView = reinterpret_cast<NSView*>(this->winId());
NSWindow *window = [nsView window];
@@ -39,7 +25,7 @@ void StatusWindow::removeTitleBar()
[titleBarContainerView setHidden:YES];
}
void StatusWindow::showTitleBar()
void StatusWindow::showTitleBarMac()
{
NSView *nsView = reinterpret_cast<NSView*>(this->winId());
NSWindow *window = [nsView window];
@@ -0,0 +1,30 @@
import QtQuick 2.14
import QtGraphicalEffects 1.14
Item {
id: root
property Item mask
property color color: "#F6F8FA"
Rectangle {
id: gradient
anchors.fill: parent
visible: false
gradient: Gradient {
orientation: Gradient.Horizontal
SkeletonGradientStop { color: "transparent"; from: -3; }
SkeletonGradientStop { color: "transparent"; from: -2; }
SkeletonGradientStop { color: root.color; from: -1 ; }
SkeletonGradientStop { color: "transparent"; from: 0; }
SkeletonGradientStop { color: "transparent"; from: 1; }
}
}
OpacityMask {
anchors.fill: parent
source: gradient
maskSource: root.mask
}
}
@@ -0,0 +1,24 @@
import QtQuick 2.14
import QtGraphicalEffects 1.14
/*
TODO: This component should be implemented as inline component of `SkeletonAnimation.qml`
when we use Qt > 5.15
*/
GradientStop {
id: root
property real from: 0
color: "transparent"
NumberAnimation on position {
easing.type: Easing.Linear
loops: Animation.Infinite
running: visible
from: root.from
to: from + 4
duration: 2000
}
}
+4
View File
@@ -0,0 +1,4 @@
module StatusQ.Animations
SkeletonAnimation 0.1 SkeletonAnimation.qml
SkeletonGradientStop 0.1 SkeletonGradientStop.qml
+3 -3
View File
@@ -4,6 +4,7 @@ import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
/// Forces size, hard to reuse it
StatusBaseText {
id: root
@@ -18,7 +19,6 @@ StatusBaseText {
color: Theme.palette.baseColor1
Component.onCompleted: {
maxWidth = width
expanded = actualWidth <= maxWidth
}
@@ -29,9 +29,9 @@ StatusBaseText {
onClicked: {
if (root.expanded) {
width = root.width = root.maxWidth
root.width = root.maxWidth
} else {
width = root.width = root.actualWidth
root.width = root.actualWidth
}
root.expanded = !root.expanded
}
@@ -0,0 +1,189 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
/*!
\qmltype StatusAddressPanel
\inherits Item
\inqmlmodule StatusQ.Components
\since StatusQ.Components 0.1
\brief Show an address as defined efined in design https://www.figma.com/file/FkFClTCYKf83RJWoifWgoX/Wallet-v2?node-id=4222%3A178403 and https://www.figma.com/file/h2Ab3k4wy1Y7SFHEvbcZZx/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop-(Copy)?node-id=1009%3A106451
Panel's components:
- Address: displays the rquired \c address property
- Frame: a rounded frame and the \c 0x icon prefix
- Copy action: clickable copy icon. Activable using \c showCopy
\qmlproperty string address address to show
\qmlproperty bool showCopy if \c true shows the copy action which triggers \c doCopy signal
\qmlproperty bool autHideCopyIcon if \c true shows the copy action when hovered. \see showCopy
\qmlproperty alias showFrame if \c true displays frame and \c 0x prefix
\qmlproperty bool expandable if \c true user can toggle between expanded and compact version; \see expanded
\qmlproperty bool expanded if \c true show address in full; if \c false show the address in compact mode eliding in the middle
\qmlproperty font: statusAddress.font
signal doCopy(string address)
\see StatusImageCrop for more details
Usage example:
\qml
StatusAddressPanel {
address: currentAccount.mixedcaseAddress
autHideCopyIcon: true
expanded: false
onDoCopy: (address) => root.store.copyToClipboard(address)
}
\endqml
For a list of components available see StatusQ.
*/
Item {
id: root
/*required*/ property string address: ""
property bool showCopy: true
property bool autHideCopyIcon: false
property alias showFrame: frameRect.visible
property bool expandable: false
property bool expanded: true
property alias font: statusAddress.font
signal doCopy(string address)
implicitWidth: frameLayout.implicitWidth
implicitHeight: frameLayout.implicitHeight
RowLayout {
id: frameLayout
anchors.fill: parent
RowLayout {
Layout.leftMargin: frameRect.visible ? 8 : undefined // Theme.geometry.halfPadding
Layout.rightMargin: Layout.leftMargin
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
Layout.minimumWidth: 120
Layout.preferredHeight: 32
spacing: 6
StatusIcon {
icon: "address"
Layout.alignment: Qt.AlignVCenter
Layout.preferredWidth: 19
Layout.preferredHeight: 19
visible: frameRect.visible
color: Theme.palette.baseColor1
opacity: 0.5
}
// Ensure the eliding is done in the middle of the value not taking into account `0x`
RowLayout {
spacing: 0
Layout.alignment: Qt.AlignVCenter
StatusBaseText {
text: "0x"
Layout.alignment: Qt.AlignVCenter
font: statusAddress.font
color: statusAddress.color
}
StatusBaseText {
id: statusAddress
text: root.address.replace("0x", "").replace("0X", "")
Layout.preferredWidth: expanded ? implicitWidth : (implicitWidth * 0.25).toFixed()
Layout.alignment: Qt.AlignVCenter
font.family: Theme.palette.monoFont.name
font.pixelSize: 15
font.weight: Font.Medium
elide: Text.ElideMiddle
color: Theme.palette.baseColor1
}
}
StatusIcon {
icon: "copy"
visible: root.autHideCopyIcon ? (mainMouseArea.containsMouse || copyMouseArea.containsMouse )
: root.showCopy
Layout.alignment: Qt.AlignVCenter
Layout.preferredWidth: (statusAddress.font.pixelSize * 1.2).toFixed()
Layout.preferredHeight: Layout.preferredWidth
color: Theme.palette.baseColor1
MouseArea {
id: copyMouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.ArrowCursor
preventStealing: true
onClicked: root.doCopy(root.address)
z: frameRect.z + 1
}
StatusIcon {
icon: parent.icon
x: 1
y: 1
width: parent.width
height: parent.height
visible: copyMouseArea.containsMouse && !copyMouseArea.pressed
color: "black"
opacity: 0.4
z: parent.z + 1
}
}
}
}
Rectangle {
id: frameRect
anchors.fill: frameLayout
color: "transparent"
border.width: 1
border.color: Theme.palette.baseColor2
radius: 36
}
MouseArea {
id: mainMouseArea
anchors.fill: parent
hoverEnabled: root.expandable || root.autHideCopyIcon
enabled: (root.autHideCopyIcon && root.showCopy) || root.expandable
acceptedButtons: root.expandable ? Qt.LeftButton : Qt.NoButton
cursorShape: root.expandable ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: root.expanded = !root.expanded
z: frameLayout.z - 1
}
}
+2
View File
@@ -30,6 +30,8 @@ Rectangle {
font.weight: Font.Medium
color: Theme.palette.statusBadge.foregroundColor
anchors.centerIn: parent
anchors.verticalCenterOffset: statusBadge.border.width/4
anchors.horizontalCenterOffset: statusBadge.border.width/4
text: {
if (statusBadge.value > 99) {
return qsTr("99+");
+498
View File
@@ -0,0 +1,498 @@
import QtQuick 2.13
import QtQuick.Layouts 1.14
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
/*!
\qmltype StatusCard
\inherits Rectangle
\inqmlmodule StatusQ.Components
\since StatusQ.Components 0.1
\brief This component represents a StatusCard as defined in design under https://www.figma.com/file/FkFClTCYKf83RJWoifWgoX/Wallet-v2?node-id=3161%3A171040
There is an advanced mode available where a StatusInput is provided for the user to be able to change values.
Example of how the component looks like:
\image status_card.png
Example of how to use it:
\qml
StatusCard {
id: card
primaryText: "Mainnet"
secondaryText: "75"
tertiaryText: "BALANCE: " + 250
cardIconName: "status"
advancedMode: false
}
\endqml
For a list of components available see StatusQ.
*/
Rectangle {
id: root
/*!
\qmlproperty string StatusCard::disabledText
This property is the text to be shown when the card is disabled
*/
property string disabledText: ""
/*!
\qmlproperty bool StatusCard::disabled
This property holds if the card is disbaled
*/
property bool disabled: false
/*!
\qmlproperty bool StatusCard::clickable
This property holds if the card is clickable
*/
property bool clickable: true
/*!
\qmlproperty bool StatusCard::advancedMode
This property holds if advanced mode is on for the StatusCard component
*/
property bool advancedMode: false
/*!
\qmlproperty int StatusCard::lockTimeout
This property enables user to customise the amount of time given to the user to enter a new value in
advanced mode before it locked for any new changes
*/
property int lockTimeout: 1500
/*!
\qmlproperty alias StatusCard::primaryText
Used to set Primary text in the StatusCard
*/
property alias primaryText: primaryText.text
/*!
\qmlproperty string StatusCard::secondaryText
Used to set Secondary text in the StatusCard
*/
property string secondaryText: ""
/*!
\qmlproperty alias StatusCard::tertiaryText
Used to set Tertiary text in the StatusCard
*/
property alias tertiaryText: tertiaryText.text
/*!
\qmlproperty alias StatusCard::advancedInputText
Used to set text in the StatusInput in advancedMode
*/
property alias advancedInputText: advancedInput.text
/*!
\qmlproperty alias StatusCard::errorIconName
Used to assign an icon to the error icon in StatusCard
*/
property alias errorIconName: errorIcon.icon
/*!
\qmlproperty alias StatusCard::cardIconName
Used to assign an icon to the card icon in StatusCard
*/
property alias cardIconName: cardIcon.icon
/*!
\qmlproperty alias StatusCard::primaryLabel
This property allows user to customize the primary label in the StatusCard
*/
property alias primaryLabel: primaryText
/*!
\qmlproperty alias StatusCard::secondaryLabel
This property allows user to customize the secondary label in the StatusCard
*/
property alias secondaryLabel: secondaryLabel
/*!
\qmlproperty alias StatusCard::tertiaryLabel
This property allows user to customize the tertiary label in the StatusCard
*/
property alias tertiaryLabel: tertiaryText
/*!
\qmlproperty alias StatusCard::advancedInput
This property allows user to customize the StatusInput in advanced mode
*/
property alias advancedInput: advancedInput
/*!
\qmlproperty alias StatusCard::errorIcon
This property allows user to customize the error icon in the StatusCard
*/
property alias errorIcon: errorIcon
/*!
\qmlproperty alias StatusCard::cardIcon
This property allows user to customize the card icon in the StatusCard
*/
property alias cardIcon: cardIcon
/*!
\qmlsignal StatusCard::clicked
This signal is emitted when the card is clicked
*/
signal clicked()
/*!
\qmlproperty string StatusCard::state
This property holds the states of the StatusCard.
Possible values are:
\ "default" : Normal state
\ "unavailable" : Unavailable state
\ "unpreferred": Not preffered state
\ "error" : Error state
*/
state: "default"
implicitHeight: advancedInput.visible ? 90 : 76
implicitWidth: 128
radius: 8
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton
enabled: root.clickable && root.state !== "unavailable"
onClicked: {
disabled = !disabled
root.clicked()
}
}
RowLayout {
id: layout
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.leftMargin: 8
anchors.rightMargin: 8
anchors.topMargin: 8
ColumnLayout {
Layout.maximumWidth: root.width - cardIcon.width - 24
StatusBaseText {
id: primaryText
Layout.maximumWidth: parent.width
font.pixelSize: 15
font.weight: Font.Medium
elide: Text.ElideRight
}
RowLayout {
id: basicInput
StatusBaseText {
id: secondaryLabel
font.pixelSize: 13
font.weight: Font.Medium
}
StatusIcon {
id: errorIcon
width: 14
height: 14
Layout.alignment: Qt.AlignTop
icon: "tiny/warning"
color: Theme.palette.pinColor1
}
}
StatusInput {
id: advancedInput
property bool locked: false
implicitWidth: 80
maximumHeight: 32
topPadding: 0
bottomPadding: 0
leftPadding: 8
rightPadding: 5
input.edit.font.pixelSize: 13
input.edit.readOnly: locked || disabled
input.rightComponent: Row {
width: implicitWidth
spacing: 4
StatusFlatRoundButton {
anchors.verticalCenter: parent.verticalCenter
width: 12
height: 12
icon.name: advancedInput.locked ? "lock" : "unlock"
icon.width: 12
icon.height: 12
icon.color: advancedInput.locked ? Theme.palette.primaryColor1 : Theme.palette.baseColor1
type: StatusFlatRoundButton.Type.Secondary
enabled: !disabled
onClicked: {
advancedInput.locked = !advancedInput.locked
waitTimer.restart()
}
}
StatusFlatRoundButton {
width: 14
height: 14
icon.name: "clear"
icon.width: 14
icon.height: 14
icon.color: Theme.palette.baseColor1
type: StatusFlatRoundButton.Type.Secondary
onClicked: advancedInput.edit.clear()
}
}
onTextChanged: {
locked = false
waitTimer.restart()
}
Timer {
id: waitTimer
interval: lockTimeout
onTriggered: {
if(advancedInput.text)
advancedInput.locked = true
}
}
}
StatusBaseText {
id: tertiaryText
font.pixelSize: 10
}
}
StatusIcon {
id: cardIcon
Layout.alignment: Qt.AlignTop | Qt.AlignRight
Layout.preferredHeight: 32
Layout.preferredWidth: 32
mipmap: true
}
}
states: [
State {
name: "default"
PropertyChanges {
target: root
color: disabled ? Theme.palette.baseColor4 : "transparent"
}
PropertyChanges {
target: root
border.color: disabled ? "transparent" : Theme.palette.primaryColor2
}
PropertyChanges {
target: primaryText
color: Theme.palette.directColor1
}
PropertyChanges {
target: primaryText
visible: primaryText.text
}
PropertyChanges {
target: secondaryLabel
color: disabled ? Theme.palette.directColor5: Theme.palette.primaryColor1
}
PropertyChanges {
target: secondaryLabel
visible: !advancedMode && secondaryLabel.text
}
PropertyChanges {
target: secondaryLabel
text: disabled ? disabledText : secondaryText
}
PropertyChanges {
target: tertiaryText
color: Theme.palette.directColor5
}
PropertyChanges {
target: tertiaryText
visible: tertiaryText.text
}
PropertyChanges {
target: cardIcon
opacity: disabled ? 0.4 : 1
}
PropertyChanges {
target: errorIcon
visible: false
}
PropertyChanges {
target: advancedInput
visible: advancedMode
}
PropertyChanges {
target: advancedInput
input.color: Theme.palette.directColor1
}
PropertyChanges {
target: basicInput
visible: !advancedMode
}
},
State {
name: "error"
PropertyChanges {
target: root
color: disabled ? Theme.palette.baseColor4 : "transparent"
}
PropertyChanges {
target: root
border.color: disabled ? "transparent" : Theme.palette.primaryColor2
}
PropertyChanges {
target: primaryText
color: Theme.palette.directColor1
}
PropertyChanges {
target: primaryText
visible: primaryText.text
}
PropertyChanges {
target: secondaryLabel
color: disabled ? Theme.palette.directColor5: Theme.palette.dangerColor1
}
PropertyChanges {
target: secondaryLabel
visible: !advancedMode && secondaryLabel.text
}
PropertyChanges {
target: secondaryLabel
text: disabled ? disabledText : secondaryText
}
PropertyChanges {
target: tertiaryText
color: disabled ? Theme.palette.directColor5 : Theme.palette.dangerColor1
}
PropertyChanges {
target: tertiaryText
visible: tertiaryText.text
}
PropertyChanges {
target: cardIcon
opacity: disabled ? 0.4 : 1
}
PropertyChanges {
target: errorIcon
visible: false
}
PropertyChanges {
target: advancedInput
visible: advancedMode
}
PropertyChanges {
target: advancedInput
input.edit.color: disabled ? Theme.palette.directColor5 : Theme.palette.dangerColor1
}
PropertyChanges {
target: basicInput
visible: !advancedMode
}
},
State {
name: "unpreferred"
PropertyChanges {
target: root
color: disabled ? Theme.palette.baseColor4 : "transparent"
}
PropertyChanges {
target: root
border.color: disabled ? "transparent": Theme.palette.pinColor2
}
PropertyChanges {
target: primaryText
color: Theme.palette.directColor1
}
PropertyChanges {
target: primaryText
visible: primaryText.text
}
PropertyChanges {
target: secondaryLabel
color: disabled ? Theme.palette.directColor5 : Theme.palette.pinColor1
}
PropertyChanges {
target: secondaryLabel
visible: !advancedMode && secondaryLabel.text
}
PropertyChanges {
target: secondaryLabel
text: disabled ? disabledText : secondaryText
}
PropertyChanges {
target: tertiaryText
color: disabled ? Theme.palette.directColor5 : Theme.palette.pinColor1
}
PropertyChanges {
target: tertiaryText
visible: tertiaryText.text
}
PropertyChanges {
target: cardIcon
opacity: disabled ? 0.4 : 1
}
PropertyChanges {
target: errorIcon
visible: !disabled && !advancedMode
}
PropertyChanges {
target: advancedInput
visible: advancedMode
}
PropertyChanges {
target: advancedInput
input.color: Theme.palette.directColor1
}
PropertyChanges {
target: basicInput
visible: !advancedMode
}
},
State {
name: "unavailable"
PropertyChanges {
target: root
color: "transparent"
}
PropertyChanges {
target: root
border.color: "transparent"
}
PropertyChanges {
target: primaryText
color: Theme.palette.directColor5
}
PropertyChanges {
target: primaryText
visible: primaryText.text
}
PropertyChanges {
target: secondaryLabel
color: Theme.palette.directColor5
}
PropertyChanges {
target: secondaryLabel
visible: secondaryLabel.text
}
PropertyChanges {
target: secondaryLabel
text: secondaryText
}
PropertyChanges {
target: tertiaryText
color: Theme.palette.directColor5
}
PropertyChanges {
target: tertiaryText
visible: tertiaryText.text
}
PropertyChanges {
target: cardIcon
opacity: 0.4
}
PropertyChanges {
target: errorIcon
visible: false
}
PropertyChanges {
target: advancedInput
visible: false
}
PropertyChanges {
target: advancedInput
input.color: Theme.palette.directColor1
}
PropertyChanges {
target: basicInput
visible: true
}
}
]}
@@ -73,6 +73,7 @@ Item {
duration: 150
direction: RotationAnimation.Clockwise
easing.type: Easing.InCubic
running: visible
}
},
Transition {
@@ -82,6 +83,7 @@ Item {
duration: 150
direction: RotationAnimation.Counterclockwise
easing.type: Easing.OutCubic
running: visible
}
}
]
+60 -31
View File
@@ -9,7 +9,7 @@ import StatusQ.Components 0.1
import StatusQ.Controls 0.1
Column {
id: statusChatList
id: root
spacing: 4
width: 288
@@ -23,8 +23,6 @@ Column {
property Component popupMenu
property var filterFn
signal chatItemSelected(string categoryId, string id)
signal chatItemUnmuted(string id)
signal chatItemReordered(string id, int from, int to)
@@ -35,22 +33,36 @@ Column {
}
}
onDraggableItemsChanged: delegateModel.items.setGroups(0, delegateModel.items.count, "unsorted")
QtObject {
id: d
property int destinationPosition: -1
}
DelegateModel {
id: delegateModel
model: statusChatList.model
model: root.model
items.includeByDefault: !root.draggableItems
groups: DelegateModelGroup {
id: unsortedItems
name: "unsorted"
includeByDefault: root.draggableItems
onChanged: Utils.delegateModelSort(unsortedItems, delegateModel.items,
(a, b) => a.position < b.position)
}
delegate: Item {
id: draggable
width: statusChatListItem.width
objectName: model.name
width: root.width
height: statusChatListItem.height
property alias chatListItem: statusChatListItem
visible: {
if (!!statusChatList.filterFn) {
return statusChatList.filterFn(model)
}
return true
}
MouseArea {
id: dragSensor
@@ -58,7 +70,7 @@ Column {
cursorShape: active ? Qt.ClosedHandCursor : Qt.PointingHandCursor
hoverEnabled: true
pressAndHoldInterval: 150
enabled: statusChatList.draggableItems
enabled: root.draggableItems
property bool active: false
property real startY: 0
@@ -74,8 +86,8 @@ Column {
}
onPressAndHold: active = true
onReleased: {
if (active) {
statusChatList.chatItemReordered(statusChatListItem.chatId, statusChatListItem.originalOrder, statusChatListItem.originalOrder)
if (active && d.destinationPosition !== -1 && statusChatListItem.originalOrder !== d.destinationPosition) {
root.chatItemReordered(statusChatListItem.chatId, statusChatListItem.originalOrder, d.destinationPosition)
}
active = false
}
@@ -89,10 +101,12 @@ Column {
active = true
}
}
onActiveChanged: d.destinationPosition = -1
StatusChatListItem {
id: statusChatListItem
width: parent.width
opacity: dragSensor.active ? 0.0 : 1.0
originalOrder: model.position
chatId: model.itemId
@@ -103,19 +117,34 @@ Column {
hasUnreadMessages: model.hasUnreadMessages
notificationsCount: model.notificationsCount
highlightWhenCreated: !!model.highlight
selected: (model.active && statusChatList.highlightItem)
icon.emoji: model.emoji
icon.color: !!model.color ? model.color : Theme.palette.userCustomizationColors[model.colorId]
image.isIdenticon: false
image.source: model.icon
selected: (model.active && root.highlightItem)
asset.emoji: !!model.emoji ? model.emoji : ""
asset.color: !!model.color ? model.color : Theme.palette.userCustomizationColors[model.colorId]
asset.isImage: model.icon.includes("data")
asset.name: model.icon
ringSettings.ringSpecModel: model.colorHash
sensor.cursorShape: dragSensor.cursorShape
Connections {
target: statusChatListItem
enabled: root.draggableItems
function onOriginalOrderChanged() {
Qt.callLater(() => {
if (!delegateModel)
return
delegateModel.items.setGroups(0, delegateModel.items.count, "unsorted")
})
}
}
onClicked: {
highlightWhenCreated = false
if (mouse.button === Qt.RightButton && !!statusChatList.popupMenu) {
if (mouse.button === Qt.RightButton && !!root.popupMenu) {
statusChatListItem.highlighted = true
let originalOpenHandler = popupMenuSlot.item.openHandler
@@ -136,17 +165,17 @@ Column {
}
}
let p = statusChatListItem.mapToItem(statusChatList, mouse.x, mouse.y)
let p = statusChatListItem.mapToItem(root, mouse.x, mouse.y)
popupMenuSlot.item.popup(p.x + 4, p.y + 6)
popupMenuSlot.item.openHandler = originalOpenHandler
return
}
if (!statusChatListItem.selected) {
statusChatList.chatItemSelected(model.parentItemId, model.itemId)
root.chatItemSelected(model.parentItemId, model.itemId)
}
}
onUnmute: statusChatList.chatItemUnmuted(model.itemId)
onUnmute: root.chatItemUnmuted(model.itemId)
}
}
@@ -157,7 +186,6 @@ Column {
keys: ["chat-item-category-" + statusChatListItem.categoryId]
onEntered: reorderDelay.start()
onDropped: statusChatList.chatItemReordered(statusChatListItem.chatId, drag.source.originalOrder, statusChatListItem.DelegateModel.itemsIndex)
Timer {
id: reorderDelay
@@ -165,7 +193,7 @@ Column {
repeat: false
onTriggered: {
if (dropArea.containsDrag) {
dropArea.drag.source.chatListItem.originalOrder = statusChatListItem.originalOrder
d.destinationPosition = delegateModel.model.get(draggable.DelegateModel.itemsIndex).position
delegateModel.items.move(dropArea.drag.source.DelegateModel.itemsIndex, draggable.DelegateModel.itemsIndex)
}
}
@@ -199,9 +227,9 @@ Column {
notificationsCount: model.notificationsCount
selected: draggable.chatListItem.selected
icon.color: draggable.chatListItem.icon.color
image.isIdenticon: draggable.chatListItem.image.isIdenticon
image.source: draggable.chatListItem.image.source
asset.color: draggable.chatListItem.asset.color
asset.imgIsIdenticon: draggable.chatListItem.asset.imgIsIdenticon
asset.name: draggable.chatListItem.asset.name
}
}
}
@@ -209,11 +237,12 @@ Column {
Repeater {
id: statusChatListItems
objectName: "chatListItems"
model: delegateModel
}
Loader {
id: popupMenuSlot
active: !!statusChatList.popupMenu
active: !!root.popupMenu
}
}
@@ -7,12 +7,16 @@ import StatusQ.Components 0.1
import StatusQ.Popups 0.1
import StatusQ.Core 0.1
import SortFilterProxyModel 0.2
Item {
id: statusChatListAndCategories
id: root
implicitHeight: chatListsAndCategories.height
implicitWidth: chatListsAndCategories.width
property alias highlightItem: statusChatList.highlightItem
property StatusTooltipSettings categoryAddButtonToolTip: StatusTooltipSettings {
text: qsTr("Add channel inside category")
}
@@ -28,7 +32,7 @@ Item {
property bool draggableCategories: false
// Keeps track of expanded category state. Should only be modified
// internally at runtime.
property var openedCategoryState: new Object({})
property var openedCategoryState: ({})
property Component categoryPopupMenu
property Component chatListPopupMenu
@@ -49,11 +53,11 @@ Item {
MouseArea {
id: sensor
anchors.top: parent.top
width: statusChatListAndCategories.width
height: statusChatListAndCategories.height
width: root.width
height: root.height
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: {
if (mouse.button === Qt.RightButton && showPopupMenu && !!statusChatListAndCategories.popupMenu) {
if (mouse.button === Qt.RightButton && showPopupMenu && !!root.popupMenu) {
popupMenuSlot.item.popup(mouse.x + 4, mouse.y + 6)
return
}
@@ -67,24 +71,50 @@ Item {
spacing: 4
StatusChatList {
objectName: "statusChatListAndCategoriesChatList"
id: statusChatList
visible: statusChatList.model.count > 0
onChatItemSelected: statusChatListAndCategories.chatItemSelected(categoryId, id)
onChatItemUnmuted: statusChatListAndCategories.chatItemUnmuted(id)
onChatItemReordered: statusChatListAndCategories.chatItemReordered(categoryId, id, from, to)
draggableItems: statusChatListAndCategories.draggableItems
model: statusChatListAndCategories.model
filterFn: function (model) {
return !model.isCategory
onChatItemSelected: root.chatItemSelected(categoryId, id)
onChatItemUnmuted: root.chatItemUnmuted(id)
onChatItemReordered: root.chatItemReordered(categoryId, id, from, to)
draggableItems: root.draggableItems
model: SortFilterProxyModel {
sourceModel: root.model
filters: ValueFilter { roleName: "isCategory"; value: false }
sorters: RoleSorter { roleName: "position" }
}
popupMenu: statusChatListAndCategories.chatListPopupMenu
popupMenu: root.chatListPopupMenu
}
DelegateModel {
id: delegateModel
model: statusChatListAndCategories.model
property int destinationPosition: -1
model: SortFilterProxyModel {
sourceModel: root.model
filters: ValueFilter { roleName: "isCategory"; value: true }
sorters: RoleSorter { roleName: "position" }
}
items.includeByDefault: false
groups: DelegateModelGroup {
id: unsortedItems
name: "unsorted"
includeByDefault: true
onChanged: Utils.delegateModelSort(unsortedItems, delegateModel.items,
(a, b) => a.position < b.position)
}
delegate: Item {
id: draggable
objectName: model.name
width: statusChatListCategory.width
height: statusChatListCategory.height
property alias chatListCategory: statusChatListCategory
@@ -102,13 +132,13 @@ Item {
dragSensor.drag.threshold: 0.1
dragSensor.drag.filterChildren: true
dragSensor.onPressAndHold: {
if (statusChatListAndCategories.draggableCategories) {
if (root.draggableCategories) {
dragActive = true
}
}
dragSensor.onReleased: {
if (dragActive) {
statusChatListAndCategories.chatListCategoryReordered(statusChatListCategory.categoryId, statusChatListCategory.originalOrder, statusChatListCategory.originalOrder)
if (dragActive && delegateModel.destinationPosition !== -1 && statusChatListCategory.originalOrder !== delegateModel.destinationPosition) {
root.chatListCategoryReordered(statusChatListCategory.categoryId, statusChatListCategory.originalOrder, delegateModel.destinationPosition)
}
dragActive = false
}
@@ -118,38 +148,44 @@ Item {
startX = dragSensor.mouseX
}
dragSensor.onMouseYChanged: {
if (statusChatListAndCategories.draggableCategories && (Math.abs(startY - dragSensor.mouseY) > 1) && dragSensor.pressed) {
if (root.draggableCategories && (Math.abs(startY - dragSensor.mouseY) > 1) && dragSensor.pressed) {
dragActive = true
}
}
dragSensor.onMouseXChanged: {
if (statusChatListAndCategories.draggableCategories && (Math.abs(startX - dragSensor.mouseX) > 1) && dragSensor.pressed) {
if (root.draggableCategories && (Math.abs(startX - dragSensor.mouseX) > 1) && dragSensor.pressed) {
dragActive = true
}
}
onDragActiveChanged: delegateModel.destinationPosition = -1
addButton.tooltip: statusChatListAndCategories.categoryAddButtonToolTip
menuButton.tooltip: statusChatListAndCategories.categoryMenuButtonToolTip
addButton.tooltip: root.categoryAddButtonToolTip
menuButton.tooltip: root.categoryMenuButtonToolTip
originalOrder: model.position
categoryId: model.itemId
name: model.name
showActionButtons: statusChatListAndCategories.showCategoryActionButtons
addButton.onClicked: statusChatListAndCategories.categoryAddButtonClicked(model.itemId)
chatList.model: model.subItems
chatList.onChatItemSelected: statusChatListAndCategories.chatItemSelected(categoryId, id)
chatList.onChatItemUnmuted: statusChatListAndCategories.chatItemUnmuted(id)
chatList.onChatItemReordered: statusChatListAndCategories.chatItemReordered(model.itemId, id, from, to)
chatList.draggableItems: statusChatListAndCategories.draggableItems
showActionButtons: root.showCategoryActionButtons
addButton.onClicked: root.categoryAddButtonClicked(model.itemId)
popupMenu: statusChatListAndCategories.categoryPopupMenu
chatListPopupMenu: statusChatListAndCategories.chatListPopupMenu
chatList.model: SortFilterProxyModel {
sourceModel: model.subItems
sorters: RoleSorter { roleName: "position" }
}
chatList.onChatItemSelected: root.chatItemSelected(categoryId, id)
chatList.onChatItemUnmuted: root.chatItemUnmuted(id)
chatList.onChatItemReordered: root.chatItemReordered(model.itemId, id, from, to)
chatList.draggableItems: root.draggableItems
popupMenu: root.categoryPopupMenu
chatListPopupMenu: root.chatListPopupMenu
// Used to set the initial value of "opened" when the
// model is bound/changed.
opened: {
let openedState = statusChatListAndCategories.openedCategoryState[model.itemId]
let openedState = root.openedCategoryState[model.itemId]
return openedState !== undefined ? openedState : true // defaults to open
}
@@ -158,7 +194,18 @@ Item {
// as the state would be lost each time the model is
// changed.
onOpenedChanged: {
statusChatListAndCategories.openedCategoryState[model.itemId] = statusChatListCategory.opened
root.openedCategoryState[model.itemId] = statusChatListCategory.opened
}
Connections {
function onOriginalOrderChanged() {
Qt.callLater(() => {
if (!delegateModel)
return
delegateModel.items.setGroups(0, delegateModel.items.count, "unsorted")
})
}
}
}
@@ -169,7 +216,6 @@ Item {
keys: ["chat-category"]
onEntered: reorderDelay.start()
onDropped: statusChatListAndCategories.chatListCategoryReordered(statusChatListCategory.categoryId, drag.source.originalOrder, statusChatListCategory.DelegateModel.itemsIndex)
Timer {
id: reorderDelay
@@ -177,7 +223,7 @@ Item {
repeat: false
onTriggered: {
if (dropArea.containsDrag) {
dropArea.drag.source.chatListCategory.originalOrder = statusChatListCategory.originalOrder
delegateModel.destinationPosition = delegateModel.model.get(draggable.DelegateModel.itemsIndex).position
delegateModel.items.move(dropArea.drag.source.DelegateModel.itemsIndex, draggable.DelegateModel.itemsIndex)
}
}
@@ -215,6 +261,7 @@ Item {
Repeater {
id: statusChatListCategories
objectName: "communityChatListCategories"
visible: !!model && model.count > 0
model: delegateModel
}
@@ -223,6 +270,6 @@ Item {
Loader {
id: popupMenuSlot
active: !!statusChatListAndCategories.popupMenu
active: !!root.popupMenu
}
}
@@ -16,6 +16,7 @@ Column {
property bool opened: true
property bool dragged: false
property alias statusChatListCategoryItem: statusChatListCategoryItem
property alias showActionButtons: statusChatListCategoryItem.showActionButtons
property alias addButton: statusChatListCategoryItem.addButton
property alias menuButton: statusChatListCategoryItem.menuButton
@@ -35,23 +36,22 @@ Column {
StatusChatListCategoryItem {
id: statusChatListCategoryItem
title: statusChatListCategory.name
visible: model.isCategory
opened: statusChatListCategory.opened
sensor.pressAndHoldInterval: 150
propagateTitleClicks: true // title click is handled as a normal click (fallthru)
showMenuButton: showActionButtons && !!statusChatListCategory.popupMenu
highlighted: statusChatListCategory.dragged
sensor.onClicked: {
onClicked: {
if (sensor.enabled) {
if (mouse.button === Qt.RightButton && showActionButtons && !!statusChatListCategory.popupMenu) {
highlighted = true;
popupMenuSlot.item.popup(mouse.x + 4, mouse.y + 6);
return
} else if (mouse.button === Qt.LeftButton) {
statusChatListCategory.opened = !statusChatListCategory.opened
}
}
}
onTitleClicked: statusChatListCategory.opened = !opened
onToggleButtonClicked: statusChatListCategory.opened = !opened
onToggleButtonClicked: statusChatListCategory.opened = !statusChatListCategory.opened
onMenuButtonClicked: {
highlighted = true
menuButton.highlighted = true
@@ -66,9 +66,6 @@ Column {
anchors.horizontalCenter: parent.horizontalCenter
visible: statusChatListCategory.opened
categoryId: statusChatListCategory.categoryId
filterFn: function (model) {
return !!model.parentItemId && model.parentItemId === statusChatList.categoryId
}
popupMenu: statusChatListCategory.chatListPopupMenu
}
@@ -60,15 +60,7 @@ StatusListItem {
icon.name: "chevron-down"
icon.width: 18
icon.rotation: statusChatListCategoryItem.opened ? 0 : 270
onPressed: {
sensor.enabled = false;
}
onClicked: {
statusChatListCategoryItem.toggleButtonClicked(mouse);
}
onReleased: {
sensor.enabled = true;
}
onClicked: statusChatListCategoryItem.toggleButtonClicked(mouse)
}
]
}
+8 -15
View File
@@ -21,11 +21,8 @@ Rectangle {
property bool hasUnreadMessages: false
property int notificationsCount: 0
property bool muted: false
property StatusImageSettings image: StatusImageSettings {
width: 24
height: 24
}
property StatusIconSettings icon: StatusIconSettings {
property StatusAssetSettings asset: StatusAssetSettings {
width: 24
height: 24
color: Theme.palette.miscColor5
@@ -85,8 +82,7 @@ Rectangle {
anchors.left: parent.left
anchors.leftMargin: 8
anchors.verticalCenter: parent.verticalCenter
image: root.image
icon: root.icon
asset: root.asset
name: root.name
}
@@ -112,17 +108,14 @@ Rectangle {
icon: {
switch (root.type) {
case StatusChatListItem.Type.PublicCat:
return Theme.palette.name == "light" ? "tiny/public-chat" : "tiny/public-chat-white"
break;
case StatusChatListItem.Type.PublicChat:
return Theme.palette.name === "light" ? "tiny/public-chat" : "tiny/public-chat-white"
case StatusChatListItem.Type.GroupChat:
return Theme.palette.name == "light" ? "tiny/group" : "tiny/group-white"
break;
return Theme.palette.name === "light" ? "tiny/group" : "tiny/group-white"
case StatusChatListItem.Type.CommunityChat:
return Theme.palette.name == "light" ? "tiny/channel" : "tiny/channel-white"
break;
return Theme.palette.name === "light" ? "tiny/channel" : "tiny/channel-white"
default:
return Theme.palette.name == "light" ? "tiny/public-chat" : "tiny/public-chat-white"
return Theme.palette.name === "light" ? "tiny/public-chat" : "tiny/public-chat-white"
}
}
}
@@ -1,179 +0,0 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.13
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
Item {
id: statusChatToolBar
property alias menuButton: menuButton
property alias notificationButton: notificationButton
property alias membersButton: membersButton
property alias searchButton: searchButton
property int padding: 8
property int notificationCount: 0
property Component popupMenu
property var toolbarComponent
signal chatInfoButtonClicked()
signal menuButtonClicked()
signal notificationButtonClicked()
signal membersButtonClicked()
signal searchButtonClicked()
implicitWidth: 518
implicitHeight: 60
onPopupMenuChanged: {
if (!!popupMenu) {
popupMenuSlot.sourceComponent = popupMenu
}
}
RowLayout {
width: parent.width
spacing: padding / 2
Loader {
id: loader
sourceComponent: statusChatToolBar.toolbarComponent
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop | Qt.AlignLeft
Layout.topMargin: padding
Layout.leftMargin: padding
}
RowLayout {
id: actionButtons
Layout.alignment: Qt.AlignTop | Qt.AlignRight
Layout.topMargin: padding
Layout.rightMargin: padding
spacing: 8
StatusFlatRoundButton {
id: searchButton
width: 32
height: 32
icon.name: "search"
type: StatusFlatRoundButton.Type.Secondary
onClicked: statusChatToolBar.searchButtonClicked()
// initializing the tooltip
tooltip.text: qsTr("Search")
tooltip.orientation: StatusToolTip.Orientation.Bottom
tooltip.y: parent.height + 12
}
StatusFlatRoundButton {
id: membersButton
width: 32
height: 32
icon.name: "group-chat"
type: StatusFlatRoundButton.Type.Secondary
onClicked: statusChatToolBar.membersButtonClicked()
// initializing the tooltip
tooltip.text: qsTr("Members")
tooltip.orientation: StatusToolTip.Orientation.Bottom
tooltip.y: parent.height + 12
}
StatusFlatRoundButton {
id: menuButton
width: 32
height: 32
icon.name: "more"
type: StatusFlatRoundButton.Type.Secondary
visible: !!statusChatToolBar.popupMenu
// initializing the tooltip
tooltip.visible: !!tooltip.text && menuButton.hovered && !popupMenuSlot.item.opened
tooltip.text: qsTr("More")
tooltip.orientation: StatusToolTip.Orientation.Bottom
tooltip.y: parent.height + 12
property bool showMoreMenu: false
onClicked: {
menuButton.highlighted = true
let originalOpenHandler = popupMenuSlot.item.openHandler
let originalCloseHandler = popupMenuSlot.item.closeHandler
popupMenuSlot.item.openHandler = function () {
if (!!originalOpenHandler) {
originalOpenHandler()
}
}
popupMenuSlot.item.closeHandler = function () {
menuButton.highlighted = false
if (!!originalCloseHandler) {
originalCloseHandler()
}
}
popupMenuSlot.item.openHandler = originalOpenHandler
popupMenuSlot.item.popup(-popupMenuSlot.item.width + menuButton.width, menuButton.height + 4)
statusChatToolBar.menuButtonClicked()
}
Loader {
id: popupMenuSlot
active: !!statusChatToolBar.popupMenu
}
}
Rectangle {
height: 24
width: 1
color: Theme.palette.directColor7
Layout.alignment: Qt.AlignVCenter
visible: notificationButton.visible &&
(menuButton.visible || membersButton.visible || searchButton.visible)
}
StatusFlatRoundButton {
id: notificationButton
width: 32
height: 32
icon.name: "notification"
icon.height: 21
type: StatusFlatRoundButton.Type.Secondary
// initializing the tooltip
tooltip.text: qsTr("Activity")
tooltip.orientation: StatusToolTip.Orientation.Bottom
tooltip.y: parent.height + 12
onClicked: statusChatToolBar.notificationButtonClicked()
StatusBadge {
id: statusBadge
visible: value > 0
anchors.top: parent.top
anchors.left: parent.right
anchors.topMargin: -3
anchors.leftMargin: {
if (statusBadge.value > 99) {
return -22
}
if (statusBadge.value > 9) {
return -21
}
return -18
}
value: statusChatToolBar.notificationCount
border.width: 2
border.color: parent.hovered ? Theme.palette.baseColor2 : Theme.palette.statusAppLayout.backgroundColor
}
}
}
}
}
@@ -160,8 +160,8 @@ Rectangle {
}
}
width: d.cardWidth
height: d.totalHeigth
implicitWidth: d.cardWidth
implicitHeight: d.totalHeigth
radius: d.bannerRadius
color: "transparent"
layer.enabled: true
@@ -360,11 +360,11 @@ Rectangle {
height: 24
radius: 20
closeButtonVisible: false
icon.emoji: model.emoji
icon.height: 24
icon.width: icon.height
icon.color: "transparent"
icon.isLetterIdenticon: true
asset.emoji: model.emoji
asset.width: 24
asset.height: 24
asset.color: "transparent"
asset.isLetterIdenticon: true
title: model.name
titleText.font.pixelSize: 13
titleText.color: d.fontColor
@@ -0,0 +1,50 @@
import QtQuick 2.14
import StatusQ.Core 0.1
import StatusQ.Controls 0.1
Item {
id: root
property string filterString
property bool showOnlySelected: false
property bool active: true
property alias model: repeater.model
property alias contentWidth: flow.width
readonly property int itemsWidth: {
let result = 0;
for (let i = 0; i < repeater.count; ++i) {
result += flow.spacing + repeater.itemAt(i).width;
}
return result;
}
signal clicked(var item)
implicitWidth: itemsWidth
implicitHeight: flow.height
Flow {
id: flow
anchors.centerIn: parent
width: Math.min(parent.width, root.itemsWidth);
spacing: 10
Repeater {
id: repeater
delegate: StatusCommunityTag {
emoji: model.emoji
name: model.name
visible: (root.showOnlySelected ? model.selected : !model.selected) &&
(filterString == 0 || name.toUpperCase().indexOf(filterString.toUpperCase()) !== -1)
width: visible ? implicitWidth : -flow.spacing
height: visible ? implicitHeight : 0
removable: root.showOnlySelected && root.active
onClicked: root.clicked(model)
}
}
}
}
@@ -6,19 +6,17 @@ import StatusQ.Core.Theme 0.1
Row {
id: root
property bool isMutualContact: false
property bool isContact: false
property var trustIndicator: StatusContactVerificationIcons.TrustedType.None
property StatusIconSettings mutualConnectionIcon: StatusIconSettings {
property StatusAssetSettings mutualConnectionIcon: StatusAssetSettings {
name: "tiny/tiny-contact"
color: Theme.palette.indirectColor1
width: dummyImage.width
height: dummyImage.height
background: StatusIconBackgroundSettings {
width: 10
height: 10
color: Theme.palette.primaryColor1
}
bgWidth: 10
bgHeight: 10
bgColor: Theme.palette.primaryColor1
// Only used to get implicit width and height from the actual image
property Image dummyImage: Image {
source: mutualConnectionIcon.name ? "../../assets/img/icons/" + mutualConnectionIcon.name + ".svg": ""
@@ -26,17 +24,15 @@ Row {
}
}
property StatusIconSettings trustContactIcon: StatusIconSettings {
property StatusAssetSettings trustContactIcon: StatusAssetSettings {
// None and Untrustworthy types, same aspect (Icon will not be visible in case of None type):
name: root.trustIndicator === StatusContactVerificationIcons.TrustedType.Verified ? "tiny/tiny-checkmark" : "tiny/subtract"
color: Theme.palette.indirectColor1
width: dummyImage.width
height: dummyImage.height
background: StatusIconBackgroundSettings {
width: 10
height: 10
color: root.trustIndicator === StatusContactVerificationIcons.TrustedType.Verified ? Theme.palette.primaryColor1 : Theme.palette.dangerColor1
}
bgWidth: 10
bgHeight: 10
bgColor: root.trustIndicator === StatusContactVerificationIcons.TrustedType.Verified ? Theme.palette.primaryColor1 : Theme.palette.dangerColor1
// Only used to get implicit width and height from the actual image
property Image dummyImage: Image {
source: trustContactIcon.name ? "../../assets/img/icons/" + trustContactIcon.name + ".svg": ""
@@ -51,29 +47,29 @@ Row {
}
spacing: 4
visible: root.isMutualContact || (root.trustIndicator !== StatusContactVerificationIcons.TrustedType.None)
visible: root.isContact || (root.trustIndicator !== StatusContactVerificationIcons.TrustedType.None)
StatusRoundIcon {
visible: root.isMutualContact
icon.name: root.mutualConnectionIcon.name
icon.width: root.mutualConnectionIcon.width
icon.height: root.mutualConnectionIcon.height
icon.rotation: root.mutualConnectionIcon.rotation
icon.color: root.mutualConnectionIcon.color
icon.background.color: root.mutualConnectionIcon.background.color
icon.background.width: root.mutualConnectionIcon.background.width
icon.background.height: root.mutualConnectionIcon.background.height
visible: root.isContact
asset.name: root.mutualConnectionIcon.name
asset.width: root.mutualConnectionIcon.width
asset.height: root.mutualConnectionIcon.height
asset.rotation: root.mutualConnectionIcon.rotation
asset.color: root.mutualConnectionIcon.color
asset.bgColor: root.mutualConnectionIcon.bgColor
asset.bgWidth: root.mutualConnectionIcon.bgWidth
asset.bgHeight: root.mutualConnectionIcon.bgHeight
}
StatusRoundIcon {
visible: root.trustIndicator !== StatusContactVerificationIcons.TrustedType.None
icon.name: root.trustContactIcon.name
icon.width: root.trustContactIcon.width
icon.height: root.trustContactIcon.height
icon.rotation: root.trustContactIcon.rotation
icon.color: root.trustContactIcon.color
icon.background.color: root.trustContactIcon.background.color
icon.background.width: root.trustContactIcon.background.width
icon.background.height: root.trustContactIcon.background.height
asset.name: root.trustContactIcon.name
asset.width: root.trustContactIcon.width
asset.height: root.trustContactIcon.height
asset.rotation: root.trustContactIcon.rotation
asset.color: root.trustContactIcon.color
asset.bgColor: root.trustContactIcon.bgColor
asset.bgWidth: root.trustContactIcon.bgWidth
asset.bgHeight: root.trustContactIcon.bgHeight
}
}
@@ -0,0 +1,42 @@
import QtQuick 2.14
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
StatusBaseText {
id: root
property int previousMessageIndex: -1
property double previousMessageTimestamp
property double messageTimestamp
font.pixelSize: 13
color: Theme.palette.baseColor1
horizontalAlignment: Text.AlignHCenter
text: {
if (previousMessageIndex === -1)
return "";
const currentMsgDate = new Date(messageTimestamp);
const prevMsgDate = new Date(previousMessageTimestamp);
if (!!prevMsgDate && currentMsgDate.getDay() === prevMsgDate.getDay())
return "";
const now = new Date();
if (now.getFullYear() == currentMsgDate.getFullYear() && now.getMonth() == currentMsgDate.getMonth() && now.getDate() == currentMsgDate.getDate())
return qsTr("Today");
const yesterday = new Date();
yesterday.setDate(now.getDate()-1);
if (yesterday.getFullYear() == currentMsgDate.getFullYear() && yesterday.getMonth() == currentMsgDate.getMonth() && yesterday.getDate() == currentMsgDate.getDate())
return qsTr("Yesterday");
// FIXME Qt6: replace with Intl.DateTimeFormat
const monthName = Qt.locale().standaloneMonthName(currentMsgDate.getMonth(), Locale.LongFormat)
if (now.getFullYear() > currentMsgDate.getFullYear())
return "%1 %2, %3".arg(monthName).arg(currentMsgDate.getDate()).arg(currentMsgDate.getFullYear())
return "%1, %2".arg(monthName).arg(currentMsgDate.getDate())
}
}
+184
View File
@@ -0,0 +1,184 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import Qt.labs.calendar 1.0
import StatusQ.Core 0.1
import StatusQ.Controls 0.1
import StatusQ.Core.Theme 0.1
/*!
\qmltype StatusDatePicker
\inherits StatusQ.Controls.StatusComboBox
\inqmlmodule StatusQ.Components
\since StatusQ.Components 0.1
\brief Displays a date picker based on a combobox with a calendar popup
The \c StatusDatePicker displays a date picker based on a combobox with a calendar popup.
The property \p selectedDate reflects the currently chosen date (defaults to today).
For a list of components available see StatusQ.
*/
StatusComboBox {
id: root
/*!
\qmlproperty string StatusDatePicker::dateFormat
This property specifies how the selected date will be displayed to the user.
By default it is current locale's short date format. For a list of available types
and formatting characters, see https://doc.qt.io/qt-5/qdate.html#toString-2
*/
property string dateFormat: Qt.locale().dateFormat(Locale.ShortFormat)
/*!
\qmlproperty date StatusDatePicker::selectedDate
This property holds the currently selected date.
\sa QtQml.Date
*/
property alias selectedDate: d.selectedDate
QtObject {
id: d
property date selectedDate: new Date()
}
control.delegate: null
control.displayText: root.selectedDate.toLocaleDateString(Qt.locale(), root.dateFormat)
control.popup.horizontalPadding: 8
control.popup.onAboutToShow: {
// always open the popup showing the last (currently) selected date
grid.year = d.selectedDate.getFullYear()
grid.month = d.selectedDate.getMonth()
}
control.popup.contentItem: Item {
property alias grid: grid
GridLayout {
anchors.fill: parent
columns: 2
RowLayout {
Layout.fillWidth: true
Layout.columnSpan: 2
spacing: 0
StatusFlatButton {
leftPadding: 8
rightPadding: 8
text: "<<"
onClicked: grid.year = grid.year - 1
StatusToolTip {
text: qsTr("Previous year")
visible: parent.hovered
}
}
StatusFlatButton {
leftPadding: 8
rightPadding: 8
text: "<"
onClicked: {
// switch to previous month (and optionally prev year in January)
const date = new Date(grid.year, grid.month)
date.setMonth(date.getMonth() - 1)
grid.month = date.getMonth()
grid.year = date.getFullYear()
}
StatusToolTip {
text: qsTr("Previous month")
visible: parent.hovered
}
}
StatusFlatButton {
Layout.fillWidth: true
text: grid.title
font.pixelSize: 18
font.weight: Font.Medium
onClicked: {
const date = new Date()
grid.month = date.getMonth()
grid.year = date.getFullYear()
}
StatusToolTip {
text: qsTr("Show current month")
visible: parent.hovered
}
}
StatusFlatButton {
leftPadding: 8
rightPadding: 8
text: ">"
onClicked: {
// switch to next month (and optionally next year in December)
const date = new Date(grid.year, grid.month)
date.setMonth(date.getMonth() + 1)
grid.month = date.getMonth()
grid.year = date.getFullYear()
}
StatusToolTip {
text: qsTr("Next month")
visible: parent.hovered
}
}
StatusFlatButton {
leftPadding: 8
rightPadding: 8
text: ">>"
onClicked: grid.year = grid.year + 1
StatusToolTip {
text: qsTr("Next year")
visible: parent.hovered
}
}
}
DayOfWeekRow {
Layout.row: 1
Layout.column: 1
Layout.fillWidth: true
delegate: StatusBaseText {
text: model.shortName
color: Theme.palette.directColor3
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
WeekNumberColumn {
id: weekColumn
month: grid.month
year: grid.year
Layout.fillHeight: true
delegate: StatusBaseText {
text: model.weekNumber
color: Theme.palette.directColor3
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
MonthGrid {
id: grid
month: d.selectedDate.getMonth()
year: d.selectedDate.getFullYear()
Layout.fillWidth: true
Layout.fillHeight: true
delegate: StatusFlatButton {
readonly property bool selected: d.selectedDate.getFullYear() === model.year &&
d.selectedDate.getMonth() === model.month &&
d.selectedDate.getDate() === model.day
opacity: model.month === grid.month ? 1 : 0.5
text: model.day
textColor: selected ? Theme.palette.primaryColor1 : Theme.palette.directColor1
font.bold: selected || model.today
onClicked: {
d.selectedDate = model.date
root.control.popup.close()
}
}
}
}
}
}
@@ -10,7 +10,7 @@ Rectangle {
property string subTitle: ""
property alias subTitleComponent: statusDescriptionListItemSubTitle
property string value: ""
property StatusIconSettings icon: StatusIconSettings {
property StatusAssetSettings asset: StatusAssetSettings {
width: 23
height: 23
}
@@ -59,7 +59,7 @@ Rectangle {
StatusFlatRoundButton {
id: statusFlatRoundButton
visible: !!statusDescriptionListItem.icon.name
visible: !!statusDescriptionListItem.asset.name
anchors.verticalCenter: statusDescriptionListItemSubTitle.verticalCenter
anchors.left: statusDescriptionListItemSubTitle.right
anchors.leftMargin: 4
@@ -67,9 +67,9 @@ Rectangle {
width: 32
height: 32
icon.name: statusDescriptionListItem.icon.name
icon.width: statusDescriptionListItem.icon.width
icon.height: statusDescriptionListItem.icon.height
icon.name: statusDescriptionListItem.asset.name
icon.width: statusDescriptionListItem.asset.width
icon.height: statusDescriptionListItem.asset.height
StatusToolTip {
id: statusToolTip
+1 -1
View File
@@ -6,7 +6,7 @@ Image {
id: root
property string emojiId: ""
width: 14
height: 14
sourceSize.width: width
+13 -20
View File
@@ -18,19 +18,13 @@ Rectangle {
property bool expandable: true
property bool expanded: false
property StatusIconSettings icon: StatusIconSettings {
width: !!statusExpandableItem.icon.name.toString() ? 24 : 40
height: !!statusExpandableItem.icon.name.toString() ? 24 : 40
property StatusAssetSettings asset: StatusAssetSettings {
width: !statusExpandableItem.asset.isImage ? 24 : 40
height: !statusExpandableItem.asset.isImage ? 24 : 40
color: Theme.palette.directColor1
background: StatusIconBackgroundSettings {
width: 32
height: 32
color: Theme.palette.primaryColor2
}
}
property StatusImageSettings image: StatusImageSettings {
width: 40
height: 40
bgWidth: 32
bgHeight: 32
bgColor: Theme.palette.primaryColor2
}
enum Type {
@@ -73,8 +67,7 @@ Rectangle {
anchors.topMargin: (statusExpandableItem.type === StatusExpandableItem.Type.Secondary) ? 12.5 : 25
anchors.left: parent.left
anchors.leftMargin: (statusExpandableItem.type === StatusExpandableItem.Type.Secondary) ? 16 : 11
image: statusExpandableItem.image
icon: statusExpandableItem.icon
asset: statusExpandableItem.asset
name: primaryText.text
active: (statusExpandableItem.type !== StatusExpandableItem.Type.Tertiary)
}
@@ -89,10 +82,10 @@ Rectangle {
anchors.verticalCenter: (statusExpandableItem.type === StatusExpandableItem.Type.Secondary) ? identicon.verticalCenter : undefined
width: !!additionalText.text ? (button.visible ? parent.width - icon.background.width - button.width - additionalText.contentWidth - 110 :
parent.width - icon.background.width - additionalText.contentWidth - 110) :
(button.visible ? parent.width - icon.background.width - button.width - 70 :
parent.width - icon.background.width - 70)
width: !!additionalText.text ? (button.visible ? parent.width - asset.bgWidth - button.width - additionalText.contentWidth - 110 :
parent.width - asset.bgWidth - additionalText.contentWidth - 110) :
(button.visible ? parent.width - asset.bgWidth - button.width - 70 :
parent.width - asset.bgWidth - 70)
font.weight: (statusExpandableItem.type === StatusExpandableItem.Type.Primary) ? Font.Medium : Font.Normal
font.pixelSize: (statusExpandableItem.type === StatusExpandableItem.Type.Primary) ? 15 : 17
@@ -217,12 +210,12 @@ Rectangle {
Transition {
from: "COLLAPSED"
to: "EXPANDED"
NumberAnimation { properties: "height"; duration: 200 }
NumberAnimation { properties: "height"; duration: 200;}
},
Transition {
from: "EXPANDED"
to: "COLLAPSED"
NumberAnimation { properties: "height"; duration: 200 }
NumberAnimation { properties: "height"; duration: 200;}
}
]
}
@@ -3,6 +3,7 @@ import QtQuick.Layouts 1.14
import StatusQ.Core 0.1
import StatusQ.Controls 0.1
import StatusQ.Core.Theme 0.1
/*!
\qmltype StatusImageCropPanel
@@ -127,12 +128,15 @@ Item {
id: mainLayout
anchors.fill: parent
spacing: 1
Item {
id: cropSpaceItem
Layout.fillWidth: true
Layout.fillHeight: true
Layout.leftMargin: 10
Layout.rightMargin: 10
clip: true
@@ -142,6 +146,7 @@ Item {
anchors.top: parent.top
anchors.right: cropEditor.left
anchors.bottom: parent.bottom
anchors.bottomMargin: -1
color: wallColor
opacity: wallTransparency
z: cropEditor.z + 1
@@ -160,8 +165,9 @@ Item {
StatusImageCrop {
id: cropEditor
anchors.centerIn: parent
width: aspectRatio < cropSpaceItem.width/cropSpaceItem.height ? cropSpaceItem.height * aspectRatio : cropSpaceItem.width - root.margins * 2
height: aspectRatio < cropSpaceItem.width/cropSpaceItem.height ? cropSpaceItem.height - root.margins * 2 : cropSpaceItem.width / aspectRatio
readonly property bool cropARSmall: aspectRatio < cropSpaceItem.width/cropSpaceItem.height
width: cropARSmall ? cropSpaceItem.height * aspectRatio : cropSpaceItem.width - root.margins * 2
height: cropARSmall ? cropSpaceItem.height - root.margins * 2 : cropSpaceItem.width / aspectRatio
}
Rectangle {
@@ -170,6 +176,7 @@ Item {
anchors.top: parent.top
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.bottomMargin: -1
color: wallColor
opacity: wallTransparency
z: cropEditor.z + 1
@@ -181,6 +188,7 @@ Item {
anchors.top: cropEditor.bottom
anchors.right: rightOverlay.left
anchors.bottom: parent.bottom
anchors.bottomMargin: -1
color: wallColor
opacity: wallTransparency
z: cropEditor.z + 1
@@ -190,6 +198,7 @@ Item {
Canvas {
visible: root.enableCheckers
anchors.fill: parent
anchors.bottomMargin: -1
onPaint: {
var ctx = getContext("2d")
for(let xI = 0; xI < Math.ceil(width/10); xI++) {
@@ -207,6 +216,7 @@ Item {
anchors.fill: parent
enabled: root.interactive
cursorShape: Qt.SizeAllCursor
property var lastDragPoint: null
onReleased: lastDragPoint = null
@@ -238,17 +248,20 @@ Item {
RowLayout {
visible: root.interactive
spacing: 10
StatusIcon {
icon: "remove-circle"
color: Theme.palette.baseColor1
Layout.preferredWidth: 20
Layout.preferredHeight: 20
Layout.alignment: Qt.AlignVCenter
Layout.preferredWidth: 24
Layout.preferredHeight: 24
}
StatusSlider {
Layout.fillWidth: true
Layout.topMargin: 20
Layout.bottomMargin: 25
Layout.topMargin: 10
Layout.bottomMargin: 10
Layout.alignment: Qt.AlignVCenter
enabled: root.interactive
@@ -261,9 +274,11 @@ Item {
}
StatusIcon {
icon: "add-circle"
color: Theme.palette.baseColor1
Layout.preferredWidth: 20
Layout.preferredHeight: 20
Layout.alignment: Qt.AlignVCenter
Layout.preferredWidth: 24
Layout.preferredHeight: 24
}
}
}
@@ -0,0 +1,232 @@
import QtQuick 2.14
import QtQuick.Layouts 1.14
import QtQuick.Controls 2.14 as QC
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Core.Utils 0.1
/*!
\qmltype StatusItemSelector
\inherits Rectangle
\inqmlmodule StatusQ.Components
\since StatusQ.Components 0.1
\brief It allows to add items and display them as a tag item with an image and text. It also allows to store and display logical `and` / `or` operators into the list. Inherits \l{https://doc.qt.io/qt-6/qml-qtquick-rectangle.html}{Item}.
The \c StatusItemSelector is populated with a data model. The data model is commonly a JavaScript array or a ListModel object with specific expected roles.
Example of how the component looks like:
\image status_item_selector.png
Example of how to use it:
\qml
StatusItemSelector {
icon: Style.svg("contact_verified")
title: qsTr("Who holds")
defaultItemText: qsTr("Example: 10 SNT")
andOperatorText: qsTr("and")
orOperatorText: qsTr("or")
CustomPopup {
id: popup
}
addButton.onClicked: {
popup.x = mouse.x
popup.y = mouse.y
popup.open()
}
}
\endqml
For a list of components available see StatusQ.
*/
Rectangle {
id: root
/*!
\qmlproperty string StatusItemSelector::icon
This property holds the icon name for the icon represented on top of the component as a title icon.
*/
property string icon
/*!
\qmlproperty int StatusItemSelector::iconSize
This property holds the icon size for the icon represented on top of the component as a title icon.
*/
property int iconSize: 18
/*!
\qmlproperty string StatusItemSelector::title
This property holds the titel shown on top of the component.
*/
property string title
/*!
\qmlproperty string StatusItemSelector::defaultItemText
This property holds the default item text shown when the list of items is empty.
*/
property string defaultItemText
/*!
\qmlproperty url StatusItemSelector::defaultItemImageSource
This property holds the default item icon shown when the list of items is empty.
*/
property url defaultItemImageSource: ""
/*!
\qmlproperty StatusRoundButton StatusItemSelector::addButton
This property holds an alias to the `add` button.
*/
readonly property alias addButton: addItemButton
/*!
\qmlproperty ListModel StatusItemSelector::itemsModel
This property holds the data that will be populated in the items selector.
Here an example of the model roles expected:
\qml
itemsModel: ListModel {
ListElement {
text: "Socks"
imageSource: "qrc:imports/assets/png/tokens/SOCKS.png"
operator: Utils.Operator.None
}
ListElement {
text: "ZRX"
imageSource: "qrc:imports/assets/png/tokens/ZRX.png"
operator: Utils.Operator.Or
}
}
\endqml
*/
property var itemsModel: ListModel { }
/*!
\qmlproperty string StatusItemSelector::andOperatorText
This property holds the string text representation for an `AND` logical operator.
*/
property string andOperatorText: qsTr("and")
/*!
\qmlproperty string StatusItemSelector::orOperatorText
This property holds the string text representation for an `OR` logical operator.
*/
property string orOperatorText: qsTr("or")
/*!
\qmlsignal StatusItemSelector::itemClicked
This signal is emitted when the item is clicked.
*/
signal itemClicked(var item, int index, var mouse)
QtObject {
id: d
function operatorTextFormat(operator) {
switch(operator) {
case Utils.Operators.And:
return root.andOperatorText
case Utils.Operators.Or:
return root.orOperatorText
case Utils.Operators.None:
return ""
}
}
}
color: Theme.palette.baseColor4
implicitHeight: columnLayout.implicitHeight + columnLayout.anchors.topMargin + columnLayout.anchors.bottomMargin
implicitWidth: 560
radius: 16
clip: true
ColumnLayout {
id: columnLayout
anchors.top: parent.top
anchors.topMargin: 12
anchors.bottomMargin: anchors.topMargin
anchors.left: parent.left
anchors.leftMargin: 16
anchors.right: parent.right
anchors.rightMargin: 16
spacing: 12
clip: true
RowLayout {
id: headerRow
spacing: 8
Image {
sourceSize.width: width || undefined
sourceSize.height: height || undefined
fillMode: Image.PreserveAspectFit
mipmap: true
antialiasing: true
width: root.iconSize
height: width
source: root.icon
}
StatusBaseText {
Layout.alignment: Qt.AlignVCenter
text: root.title
color: Theme.palette.directColor1
font.pixelSize: 17
}
}
Flow {
id: flow
Layout.fillWidth: true
spacing: 6
StatusListItemTag {
visible: itemsModel.count === 0
title: root.defaultItemText
asset.name: root.defaultItemImageSource
asset.isImage: true
color: Theme.palette.baseColor2
closeButtonVisible: false
titleText.color: Theme.palette.baseColor1
titleText.font.pixelSize: 15
}
Repeater {
model: itemsModel
RowLayout {
spacing: flow.spacing
StatusBaseText {
visible: model.operator !== Utils.Operators.None
Layout.alignment: Qt.AlignVCenter
text: d.operatorTextFormat(model.operator)
color: Theme.palette.primaryColor1
font.pixelSize: 17
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
// Switch operator
if(model.operator === Utils.Operators.And)
model.operator = Utils.Operators.Or
else
model.operator = Utils.Operators.And
}
}
}
StatusListItemTag {
title: model.text
asset.name: model.imageSource
asset.isImage: true
color: Theme.palette.primaryColor3
closeButtonVisible: false
titleText.color: Theme.palette.primaryColor1
titleText.font.pixelSize: 15
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: root.itemClicked(parent, model.index, mouse)
}
}
}
}
StatusRoundButton {
id: addItemButton
implicitHeight: 32
implicitWidth: implicitHeight
height: width
type: StatusRoundButton.Type.Secondary
icon.name: "add"
}
}
}
}
+107 -46
View File
@@ -5,6 +5,10 @@ import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Components 0.1
import StatusQ.Controls 0.1
import StatusQ.Animations 0.1
import QtGraphicalEffects 1.14
import "private"
Rectangle {
id: statusListItem
@@ -16,46 +20,43 @@ Rectangle {
property string subTitle: ""
property string tertiaryTitle: ""
property string label: ""
property string titleTextIcon: ""
property real leftPadding: 16
property real rightPadding: 16
property bool enabled: true
property bool highlighted: false
property bool propagateTitleClicks: true
property int type: StatusListItem.Type.Primary
property list<Item> components
property var bottomModel: []
property Component bottomDelegate
property var tagsModel: []
property alias tagsModel: tagsRepeater.model
property Component tagsDelegate
property bool loading: false
property bool loadingFailed: false
property StatusIconSettings icon: StatusIconSettings {
height: isLetterIdenticon ? 40 : 20
width: isLetterIdenticon ? 40 : 20
property StatusAssetSettings asset: StatusAssetSettings {
height: isImage ? 40 : 20
width: isImage ? 40 : 20
rotation: 0
isLetterIdenticon: false
letterSize: 21
charactersLen: 1
color: isLetterIdenticon ? background.color : type === StatusListItem.Type.Danger ?
color: isLetterIdenticon ? bgColor : type === StatusListItem.Type.Danger ?
Theme.palette.dangerColor1 : Theme.palette.primaryColor1
background: StatusIconBackgroundSettings {
width: 40
height: 40
color: {
if (sensor.containsMouse) {
return type === StatusListItem.Type.Secondary ||
type === StatusListItem.Type.Danger ? "transparent" :
Theme.palette.primaryColor3
}
return type === StatusListItem.Type.Danger ?
Theme.palette.dangerColor3 : Theme.palette.primaryColor3
bgWidth: 40
bgHeight: 40
bgColor: {
if (sensor.containsMouse) {
return type === StatusListItem.Type.Secondary ||
type === StatusListItem.Type.Danger ? "transparent" :
Theme.palette.primaryColor3
}
return type === StatusListItem.Type.Danger ?
Theme.palette.dangerColor3 : Theme.palette.primaryColor3
}
imgIsIdenticon: false
}
property StatusImageSettings image: StatusImageSettings {
width: 40
height: 40
isIdenticon: false
}
property StatusIdenticonRingSettings ringSettings: StatusIdenticonRingSettings {
initalAngleRad: 0
ringPxSize: 1.5
@@ -115,36 +116,50 @@ Rectangle {
}
MouseArea {
id: sensor
enabled: statusListItem.enabled
anchors.fill: parent
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton
hoverEnabled: true
preventStealing: true
onClicked: {
statusListItem.clicked(statusListItem.itemId, mouse)
}
}
MouseArea {
id: sensor
anchors.fill: parent
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
acceptedButtons: Qt.NoButton
hoverEnabled: true
StatusSmartIdenticon {
id: iconOrImage
anchors.left: parent.left
anchors.leftMargin: statusListItem.leftPadding
anchors.top: parent.top
anchors.topMargin: 12
image: statusListItem.image
icon: statusListItem.icon
anchors.verticalCenter: parent.verticalCenter
visible: !iconOrImageLoadingOverlay.visible
asset: statusListItem.asset
name: statusListItem.title
active: statusListItem.icon.isLetterIdenticon ||
!!statusListItem.icon.name ||
!!statusListItem.image.source.toString() ||
!!statusListItem.icon.emoji
active: statusListItem.asset.isLetterIdenticon ||
!!statusListItem.asset.name ||
!!statusListItem.asset.emoji
badge.border.color: statusListItem.color
ringSettings: statusListItem.ringSettings
}
Rectangle {
id: iconOrImageLoadingOverlay
visible: statusListItem.loading || statusListItem.loadingFailed
anchors.fill: iconOrImage
radius: width / 2
color: statusListItem.loadingFailed ? Theme.palette.dangerColor2 : Theme.palette.baseColor1
SkeletonAnimation {
anchors.fill: parent
mask: parent
visible: statusListItem.loading && !statusListItem.loadingFailed
}
}
Item {
id: statusListItemTitleArea
@@ -159,13 +174,34 @@ Rectangle {
anchors.left: iconOrImage.active ? iconOrImage.right : parent.left
anchors.right: statusListItemLabel.visible ? statusListItemLabel.left : statusListItemComponentsSlot.left
anchors.leftMargin: iconOrImage.active ? 16 : statusListItem.leftPadding
anchors.rightMargin: statusListItem.rightPadding
anchors.rightMargin: Math.max(statusListItem.rightPadding, titleIconsRow.requiredWidth)
anchors.verticalCenter: bottomModel.length === 0 ? parent.verticalCenter : undefined
height: childrenRect.height
Rectangle {
id: titleLoadingOverlay
visible: statusListItem.loading || statusListItem.loadingFailed
anchors {
left: statusListItemTitle.left
top: statusListItemTitle.top
bottom: statusListItemTitle.bottom
}
width: Math.max(95, statusListItemTitle.width)
radius: 4
color: statusListItem.loadingFailed ? Theme.palette.dangerColor2 : Theme.palette.baseColor1
SkeletonAnimation {
anchors.fill: parent
mask: parent
visible: statusListItem.loading && !statusListItem.loadingFailed
}
}
StatusBaseText {
id: statusListItemTitle
opacity: titleLoadingOverlay.visible ? 0 : 1
text: statusListItem.title
font.pixelSize: 15
height: visible ? contentHeight : 0
@@ -188,6 +224,16 @@ Rectangle {
}
}
StatusIcon {
width: visible ? 12 : 0
height: visible ? 12 : 0
visible: !!statusListItem.titleTextIcon
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: statusListItemTitle.contentWidth + 6
icon: statusListItem.titleTextIcon
}
StatusToolTip {
id: statusListItemTitleTooltip
text: statusListItemTitle.text
@@ -224,6 +270,9 @@ Rectangle {
Loader {
id: titleIconsRow
readonly property int requiredWidth: active ? width + anchors.leftMargin * 2 : 0
anchors.left: !statusListItem.titleAsideText ? statusListItemTitle.right : statusListItemTitleAsideText.right
anchors.verticalCenter: statusListItemTitle.verticalCenter
anchors.leftMargin: 4
@@ -231,11 +280,15 @@ Rectangle {
StatusBaseText {
id: statusListItemSubTitle
objectName: "statusListItemSubTitle"
anchors.top: statusListItemTitle.bottom
width: parent.width
text: statusListItem.subTitle
font.pixelSize: 15
color: !statusListItem.enabled || !statusListItem.tertiaryTitle ? Theme.palette.baseColor1 : Theme.palette.directColor1
color: statusListItem.loadingFailed ? Theme.palette.dangerColor1
: !statusListItem.enabled || !statusListItem.tertiaryTitle
? Theme.palette.baseColor1
: Theme.palette.directColor1
height: visible ? contentHeight : 0
visible: !!statusListItem.subTitle
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
@@ -260,16 +313,24 @@ Rectangle {
implicitHeight: visible ? 22 : 0
}
Row {
id: statusListItemTagsSlotInline
ScrollView {
visible: tagsRepeater.count > 0
anchors.top: statusListItemTertiaryTitle.bottom
anchors.topMargin: visible? 8 : 0
width: parent.width
spacing: 10
height: visible? contentHeight + 12 : contentHeight
clip: true
Repeater {
model: tagsModel
delegate: tagsDelegate
ScrollBar.vertical.policy: ScrollBar.AlwaysOff
Row {
id: statusListItemTagsSlotInline
spacing: 10
Repeater {
id: tagsRepeater
delegate: tagsDelegate
}
}
}
}
@@ -294,7 +355,7 @@ Rectangle {
id: statusListItemLabel
anchors.verticalCenter: bottomModel.length === 0 ? parent.verticalCenter : undefined
anchors.top: bottomModel.length === 0 ? undefined: parent.top
anchors.topMargin: bottomModel.length === 0 ? undefined : 16
anchors.topMargin: bottomModel.length === 0 ? 0 : 16
anchors.right: statusListItemComponentsSlot.left
anchors.rightMargin: statusListItemComponentsSlot.width > 0 ? 10 : 0
+13 -18
View File
@@ -13,17 +13,12 @@ Control {
property string primaryText: ""
property string secondaryText: ""
property StatusImageSettings image: StatusImageSettings {
height: 16
width: 16
isIdenticon: false
}
property StatusIconSettings icon: StatusIconSettings {
property StatusAssetSettings asset: StatusAssetSettings {
height: 16
width: 16
isLetterIdenticon: false
background: StatusIconBackgroundSettings {}
color: "transparent"
imgIsIdenticon: false
}
background: Rectangle {
@@ -43,22 +38,22 @@ Control {
anchors.horizontalCenterOffset: -spacing
spacing: 2
StatusRoundedImage {
implicitWidth: root.image.width
implicitHeight: root.image.height
visible: !root.icon.isLetterIdenticon
image.source: root.image.source
implicitWidth: root.asset.width
implicitHeight: root.asset.height
visible: !root.asset.isLetterIdenticon
image.source: root.asset.name
border.color: Theme.palette.baseColor1
border.width: root.image.isIdenticon ? 1 : 0
border.width: root.asset.imgIsIdenticon ? 1 : 0
}
StatusLetterIdenticon {
implicitWidth: root.icon.width
implicitHeight: root.icon.width
implicitWidth: root.asset.width
implicitHeight: root.asset.width
letterSize: 11
visible: root.icon.isLetterIdenticon
color: root.icon.color
visible: root.asset.isLetterIdenticon
color: root.asset.color
name: root.primaryText
emoji: root.icon.emoji
emojiSize: root.icon.emojiSize
emoji: root.asset.emoji
emojiSize: root.asset.emojiSize
}
StatusBaseText {
font.weight: Font.Medium
+12 -23
View File
@@ -6,8 +6,8 @@ import StatusQ.Core.Theme 0.1
Rectangle {
id: root
width: layout.width + layout.anchors.margins
height: 30
implicitWidth: layout.width + layout.anchors.margins
implicitHeight: 30
color: Theme.palette.primaryColor3
radius: 15
@@ -15,26 +15,19 @@ Rectangle {
property string title: ""
property bool closeButtonVisible: true
signal clicked()
signal clicked(var mouse)
property StatusImageSettings image: StatusImageSettings {
width: 20
height: 20
isIdenticon: false
}
property StatusIconSettings icon: StatusIconSettings {
property StatusAssetSettings asset: StatusAssetSettings {
height: 20
width: 20
rotation: 0
isLetterIdenticon: false
letterSize: 10
color: Theme.palette.primaryColor1
background: StatusIconBackgroundSettings {
width: 15
height: 15
color: Theme.palette.primaryColor3
}
bgWidth: 15
bgHeight: 15
bgColor: Theme.palette.primaryColor3
imgIsIdenticon: false
}
RowLayout {
@@ -45,12 +38,10 @@ Rectangle {
StatusSmartIdenticon {
id: iconOrImage
Layout.leftMargin: 4
image: root.image
icon: root.icon
asset: root.asset
name: root.title
active: root.icon.isLetterIdenticon ||
!!root.icon.name ||
!!root.image.source.toString()
active: root.asset.isLetterIdenticon ||
!!root.asset.name
}
StatusBaseText {
@@ -70,9 +61,7 @@ Rectangle {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
root.clicked()
}
onClicked: root.clicked(mouse)
}
}
}
+74 -97
View File
@@ -6,6 +6,8 @@ import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import SortFilterProxyModel 0.2
/*!
\qmltype StatusListPicker
\inherits Item
@@ -15,7 +17,7 @@ import StatusQ.Controls 0.1
The \c StatusListPicker is populated with a data model. The data model is commonly a JavaScript array or a ListModel object.
StatusListPicker can be made as a single or multiple options picker by setting its StatusListPicker::multiSelection property properly or will be auto-set if the model contains / provides more than one selected items.
StatusListPicker can be made as a single or multiple options picker by setting its StatusListPicker::multiSelection property properly.
The StatusPickerButton text holds the text of the current item selected in the list picker. If there is more than one item selected, a string composed will be displayed.
The drop-down list incorporates a searcher by the following model roles: `name` or / and `shortName`.
@@ -44,6 +46,7 @@ Item {
This property holds the data that will be populated in the list picker.
NOTE: This model property should not change so it is an in / out property where the selected role will be dynamically changed according to user actions.
NOTE: Be sure provided model is compatible with StatusListPicker::multiSelection property.
Here an example of the model roles expected:
\qml
@@ -69,7 +72,9 @@ Item {
}
\endqml
*/
property ListModel inputList: ListModel { }
property var inputList: ListModel { }
readonly property StatusListPickerProxies proxy: StatusListPickerProxies {}
/*!
\qmlproperty string StatusListPicker::searchText
@@ -151,94 +156,66 @@ Item {
QtObject {
id: d
property var filteredModel: ListModel { }
// Used to set up component and the needed private properties
function initialize() {
if(filteredModel.count === 0) {
// It is necessary to load the model, not loaded yet!
var selected = 0
var selectionText = ""
for(var i = 0; i < root.inputList.count; i++) {
var item = root.inputList.get(i)
d.filteredModel.append(item)
if(item.selected) selected++;
}
// If the given model has more than one selected elements, the behaviour of the list picker will be as a multiple selector with checkboxes although it is
// set in the radiobutton mode. Radiobutton mode is only for mutial-exclusion.
if(selected > 1)
multiSelection = true
// Update selected items text:
d.getSelectedItemsText()
readonly property SortFilterProxyModel selectedItems: SortFilterProxyModel {
sourceModel: root.inputList
// NOTE: ValueFilter would crash if source model does not contain given role
// FIXME: use ValueFilter when its fixed
filters: ExpressionFilter {
expression: root.proxy.selected(model)
}
}
// Used to update model elements given a specific text by filtering them for its `name` and / or `shortName`.
function applyFilter(text) {
const input = text.toLowerCase()
filteredModel.clear()
for(var i = 0; i < root.inputList.count; i++) {
let item = root.inputList.get(i)
if(item.name.toLowerCase().includes(input) || item.shortName.toLowerCase().includes(input))
filteredModel.append(item)
readonly property string selectedItemsText: {
function formatSymbolShortNameText(symbol, shortName) {
var formattedText = ""
if(root.printSymbol && symbol)
formattedText = symbol + shortName
else
formattedText = shortName
return formattedText
}
}
function formatSymbolShortNameText(symbol, shortName) {
var formattedText = ""
if(root.printSymbol && symbol)
formattedText = symbol + shortName
else
formattedText = shortName
return formattedText
}
function getSelectedItemsText() {
var res = ""
for(var i = 0; i < root.inputList.count; i++) {
var item = root.inputList.get(i)
if(item.selected) {
if(res != "")
res += ", "
res += d.formatSymbolShortNameText(item.symbol, item.shortName)
}
for(var i = 0; i < selectedItems.count; i++) {
var item = selectedItems.get(i)
if(res != "")
res += ", "
res += formatSymbolShortNameText(root.proxy.symbol(item), root.proxy.shortName(item))
}
return res
}
// Used to update the base input list model with the new selected property
function updateInputListModel(key, selected, isSingleSelection) {
// If it is a single selection we must ensure that when a new key is selected others are cleared.
// It must be done manually because as there is the option of filterning, the model visualized changes
// and it could be possible to have a filtered list without an element selected (but in the base model
// it is) so, the binding to not selected will not be executed, as in the current filtered model
// there are no changes to update, just only the selected one.
for(var i = 0; i < root.inputList.count; i++) {
if(root.inputList.get(i).key === key) {
root.inputList.get(i).selected = selected
}
else if(isSingleSelection && selected) {
// Clear all the list
root.inputList.get(i).selected = false
}
}
}
}
width: 110
height: 38
Component.onCompleted: d.initialize()
Repeater {
// Used to update the base input list model with the new selected property
// If it is a single selection we must ensure that when a new key is selected others are cleared.
id: itemsSelectorHelper
signal selectItem(var key, bool checked)
model: root.inputList
delegate: Item {
Connections {
target: itemsSelectorHelper
function onSelectItem(key, checked) {
if (root.proxy.key(model) === key) root.proxy.setSelected(model, checked)
else if (!root.multiSelection && checked) root.proxy.setSelected(model, false)
}
}
}
}
StatusPickerButton {
id: btn
anchors.fill: parent
bgColor: Theme.palette.primaryColor3
contentColor: Theme.palette.primaryColor1
text: picker.selectedItemsText
textPixelSize: 13
text: d.selectedItemsText
font.pixelSize: 13
type: StatusPickerButton.Type.Down
onClicked: {
@@ -253,8 +230,6 @@ Item {
Rectangle {
id: picker
property string selectedItemsText: ""
width: content.itemWidth
height: Math.min(content.contentHeight + content.anchors.topMargin + content.anchors.bottomMargin, root.maxPickerHeight)
anchors.left: root.menuAlignment === StatusListPicker.MenuAlignment.Left ? btn.left : undefined
@@ -277,12 +252,23 @@ Item {
}
ListView {
id: content
id: content
property int itemHeight: 40
property int itemWidth: 360
model: d.filteredModel
model: SortFilterProxyModel {
sourceModel: root.inputList
delayed: true
filters: ExpressionFilter {
expression: {
root.searchText // ensure expression is reevaluated when searchText changes
return root.proxy.name(model).toLowerCase().includes(root.searchText.toLowerCase()) ||
root.proxy.shortName(model).toLowerCase().includes(root.searchText.toLowerCase())
}
}
}
width: itemWidth
anchors.top: parent.top
anchors.topMargin: 8
@@ -298,9 +284,9 @@ Item {
color: Theme.palette.statusPopupMenu.backgroundColor
z: 3 // Above delegate (z=1) and above section.delegate (z = 2)
StatusBaseInput {
StatusInput {
id: searchInput
implicitHeight: 36
maximumHeight: 36
width: content.itemWidth - 2 * 18
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
@@ -308,43 +294,34 @@ Item {
bottomPadding: 0
placeholderText: root.placeholderSearchText
text: root.searchText
icon.name: "search"
input.asset.name: "search"
onTextChanged: {
d.applyFilter(text)
root.searchText = text
}
onTextChanged: root.searchText = text
}
}// End of search input item
delegate: StatusItemPicker {
width: content.itemWidth
height: content.itemHeight
color: mouseArea.containsMouse ? Theme.palette.baseColor4 : "transparent"
image: StatusImageSettings {
source: model.imageSource ? model.imageSource : ""
asset: StatusAssetSettings {
name: root.proxy.imageSource(model) ? root.proxy.imageSource(model) : ""
width: 15
height: 15
isIdenticon: false
imgIsIdenticon: false
}
name: model.name
shortName: model.shortName
name: root.proxy.name(model)
shortName: root.proxy.shortName(model)
selectorType: root.multiSelection ? StatusItemPicker.SelectorType.CheckBox : StatusItemPicker.SelectorType.RadioButton
selected: model.selected
selected: root.proxy.selected(model)
radioGroup: radioBtnGroup
onCheckedChanged: {
d.updateInputListModel(model.key, checked, selectorType === StatusItemPicker.SelectorType.RadioButton)
if(selectorType === StatusItemPicker.SelectorType.RadioButton && checked) {
// Update selected item text
picker.selectedItemsText = d.formatSymbolShortNameText(model.symbol, model.shortName)
}
else {
// Update selected items text (multiple selection, text chain).
picker.selectedItemsText = d.getSelectedItemsText()
if (checked !== root.proxy.selected(model)) {
itemsSelectorHelper.selectItem(root.proxy.key(model), checked)
}
// Used to notify selected property changes in the specific item picker.
itemPickerChanged(model.key, checked)
itemPickerChanged(root.proxy.key(model), checked)
}
MouseArea {
@@ -386,7 +363,7 @@ Item {
// Not visual element to control mutual-exclusion of radiobuttons that are not sharing the same parent (inside list view)
ButtonGroup {
id: radioBtnGroup
}
}// End of Content
}
}// End of Content
}// End of Rectangle picker
}
@@ -0,0 +1,30 @@
import QtQuick 2.14
/*!
Enables StatusListPicker to work with incompatible models.
\qml
StatusListPicker {
id: currencyPicker
inputList: ListModel {
ListElement { incompatibleA: 0 ... incomatibleZ: false }
ListElement { incompatibleA: 1 ... incomatibleZ: false }
ListElement { incompatibleA: 2 ... incomatibleZ: false }
}
proxy { // StatusListPickerProxies
key: (model) => model.incompatibleA
...
selected: (model) => model.incompatibleZ
}
}
\endqml
*/
QtObject {
property var key: (model) => model.key
property var name: (model) => model.name
property var shortName: (model) => model.shortName
property var symbol: (model) => model.symbol
property var imageSource: (model) => model.imageSource
property var category: (model) => model.category
property var selected: (model) => model.selected
property var setSelected: (model, val) => model.selected = val
}
@@ -11,7 +11,7 @@ StatusIcon {
from: 0;
to: 360;
duration: 1200
running: true
running: visible
loops: Animation.Infinite
}
}
@@ -111,7 +111,7 @@ StatusListItem {
// root object settings:
title: (root.nickName === "") ? root.userName : root.nickName
statusListItemTitleIcons.sourceComponent: StatusContactVerificationIcons {
isMutualContact: root.isContact
isContact: root.isContact
trustIndicator: {
if (root.isVerified) return StatusContactVerificationIcons.TrustedType.Verified
else if (root.isUntrustworthy) return StatusContactVerificationIcons.TrustedType.Untrustworthy
@@ -120,7 +120,6 @@ StatusListItem {
}
subTitle: d.composeSubtitile()
statusListItemSubTitle.font.pixelSize: 10
icon.isLetterIdenticon: !root.image.source.toString()
statusListItemIcon.badge.visible: true
statusListItemIcon.badge.color: root.status === 1 ? Theme.palette.successColor1 : Theme.palette.baseColor1 // FIXME
color: sensor.containsMouse ? Theme.palette.baseColor2 : Theme.palette.baseColor4
@@ -129,10 +128,8 @@ StatusListItem {
implicitWidth: 256
implicitHeight: Math.max(56, statusListItemTitleArea.height + leftPadding)
leftPadding: 8
image.width: 32
image.height: 32
icon.width: 32
icon.height: 32
asset.width: 32
asset.height: 32
statusListItemIcon.anchors.verticalCenter: sensor.verticalCenter
statusListItemIcon.anchors.top: undefined
statusListItemIcon.badge.border.width: 2
+294 -85
View File
@@ -1,14 +1,16 @@
import QtQuick 2.14
import QtQuick.Layouts 1.14
import QtQuick.Controls 2.14
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Core.Utils 0.1
import StatusQ.Controls 0.1
import "./private/statusMessage"
Rectangle {
id: statusMessage
id: root
enum ContentType {
Unknown = 0,
@@ -21,12 +23,12 @@ Rectangle {
Invitation = 7
}
property alias messageHeader: messageHeader
property alias quickActions:quickActionsPanel.quickActions
property alias quickActions: quickActionsPanel.items
property alias statusChatInput: editComponent.inputComponent
property alias linksComponent: linksLoader.sourceComponent
property alias footerComponent: footer.sourceComponent
property alias timestamp: messageHeader.timestamp
property alias transcationComponent: transactionBubbleLoader.sourceComponent
property alias invitationComponent: invitationBubbleLoader.sourceComponent
property alias mouseArea: mouseArea
property string resendText: ""
property string cancelButtonText: ""
@@ -35,155 +37,362 @@ Rectangle {
property string errorLoadingImageText: ""
property string audioMessageInfoText: ""
property string pinnedMsgInfoText: ""
property var reactionIcons: [
Emoji.iconSource("❤"),
Emoji.iconSource("👍"),
Emoji.iconSource("👎"),
Emoji.iconSource("🤣"),
Emoji.iconSource("😥"),
Emoji.iconSource("😠")
]
property string messageId: ""
property bool isAppWindowActive: false
property bool editMode: false
property bool isAReply: false
property bool isEdited: false
property bool isChatBlocked: false
property bool hasMention: false
property bool isPinned: false
property string pinnedBy: ""
property bool hasExpired: false
property double timestamp: 0
property var reactionsModel: []
readonly property bool dateGroupVisible: dateGroupLabel.visible
property bool showHeader: true
property bool isActiveMessage: false
property bool disableHover: false
property bool hideQuickActions: false
property color overrideBackgroundColor: "transparent"
property bool overrideBackground: false
property bool profileClickable: true
property alias previousMessageIndex: dateGroupLabel.previousMessageIndex
property alias previousMessageTimestamp: dateGroupLabel.previousMessageTimestamp
property StatusMessageDetails messageDetails: StatusMessageDetails {}
property StatusMessageDetails replyDetails: StatusMessageDetails {}
signal profilePictureClicked()
signal senderNameClicked()
signal editCompleted(var newMsgText)
signal replyProfileClicked()
signal stickerLoaded()
signal imageClicked(var imageSource)
property string timestampString: Qt.formatTime(new Date(timestamp), "hh:mm");
property string timestampTooltipString: Qt.formatTime(new Date(timestamp), "dddd, MMMM d, yyyy hh:mm:ss t");
signal clicked(var sender, var mouse)
signal profilePictureClicked(var sender, var mouse)
signal senderNameClicked(var sender, var mouse)
signal replyProfileClicked(var sender, var mouse)
signal addReactionClicked(var sender, var mouse)
signal toggleReactionClicked(int emojiId)
signal imageClicked(var image, var mouse, var imageSource)
signal stickerClicked()
signal resendClicked()
height: childrenRect.height
color: hoverHandler.hovered ? (messageDetails.hasMention ? Theme.palette.mentionColor3 : messageDetails.isPinned ? Theme.palette.pinColor2 : Theme.palette.baseColor2) : messageDetails.hasMention ? Theme.palette.mentionColor4 : messageDetails.isPinned ? Theme.palette.pinColor3 : "transparent"
signal editCompleted(var newMsgText)
signal editCancelled()
signal stickerLoaded()
signal linkActivated(string link)
signal hoverChanged(string messageId, bool hovered)
signal activeChanged(string messageId, bool active)
function startMessageFoundAnimation() {
messageFoundAnimation.start();
}
implicitWidth: messageLayout.implicitWidth
+ messageLayout.anchors.leftMargin
+ messageLayout.anchors.rightMargin
implicitHeight: messageLayout.implicitHeight
+ messageLayout.anchors.topMargin
+ messageLayout.anchors.bottomMargin
color: {
if (root.overrideBackground)
return root.overrideBackgroundColor;
if (root.editMode)
return Theme.palette.baseColor2;
if (hoverHandler.hovered || root.isActiveMessage) {
if (root.hasMention)
return Theme.palette.mentionColor3;
if (root.isPinned)
return Theme.palette.pinColor2;
return Theme.palette.baseColor2;
}
if (root.hasMention)
return Theme.palette.mentionColor4;
if (root.isPinned)
return Theme.palette.pinColor3;
return "transparent";
}
Rectangle {
anchors {
top: parent.top
bottom: parent.bottom
left: parent.left
}
width: 2
visible: root.isPinned
color: Theme.palette.pinColor1
}
Rectangle {
anchors {
top: parent.top
bottom: parent.bottom
left: parent.left
}
width: 2
visible: root.hasMention
color: Theme.palette.mentionColor1
}
SequentialAnimation {
id: messageFoundAnimation
PauseAnimation {
duration: 600
}
NumberAnimation {
target: highlightRect
property: "opacity"
to: 1.0
duration: 1500
}
PauseAnimation {
duration: 1000
}
NumberAnimation {
target: highlightRect
property: "opacity"
to: 0.0
duration: 1500
}
}
Rectangle {
id: highlightRect
anchors.fill: parent
opacity: 0
visible: opacity > 0.001
color: Theme.palette.baseColor2
}
MouseArea {
id: mouseArea
anchors.fill: parent
}
HoverHandler {
id: hoverHandler
enabled: !root.isActiveMessage && !root.disableHover
}
ColumnLayout {
id: messageLayout
width: parent.width
StatusMessageReply {
anchors.fill: parent
anchors.topMargin: 8
anchors.bottomMargin: 8
StatusDateGroupLabel {
id: dateGroupLabel
Layout.fillWidth: true
visible: isAReply
replyDetails: statusMessage.replyDetails
onReplyProfileClicked: statusMessage.replyProfileClicked()
audioMessageInfoText: statusMessage.audioMessageInfoText
Layout.topMargin: 20
messageTimestamp: root.timestamp
visible: text !== ""
}
RowLayout {
spacing: 8
Loader {
Layout.fillWidth: true
StatusSmartIdenticon {
id: profileImage
active: isAReply
visible: active
sourceComponent: StatusMessageReply {
replyDetails: root.replyDetails
profileClickable: root.profileClickable
onReplyProfileClicked: root.replyProfileClicked(sender, mouse)
audioMessageInfoText: root.audioMessageInfoText
}
}
RowLayout {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
spacing: 8
Item {
implicitWidth: profileImage.width
implicitHeight: profileImage.visible ? profileImage.height : 0
Layout.alignment: Qt.AlignTop
Layout.topMargin: 10
Layout.leftMargin: 16
image: messageDetails.profileImage
name: messageHeader.displayName
MouseArea {
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton
anchors.fill: parent
onClicked: statusMessage.profilePictureClicked()
StatusSmartIdenticon {
id: profileImage
active: root.showHeader
visible: active
name: root.messageDetails.sender.userName
asset: root.messageDetails.sender.profileImage.assetSettings
ringSettings: root.messageDetails.sender.profileImage.ringSettings
MouseArea {
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton
anchors.fill: parent
enabled: root.profileClickable
onClicked: root.profilePictureClicked(this, mouse)
}
}
}
Column {
ColumnLayout {
spacing: 4
Layout.alignment: Qt.AlignTop
Layout.topMargin: 10
Layout.fillWidth: true
StatusPinMessageDetails {
visible: messageDetails.isPinned && !editMode
pinnedMsgInfoText: statusMessage.pinnedMsgInfoText
pinnedBy: messageDetails.pinnedBy
Loader {
active: root.isPinned && !editMode
visible: active
sourceComponent: StatusPinMessageDetails {
pinnedMsgInfoText: root.pinnedMsgInfoText
pinnedBy: root.pinnedBy
}
}
StatusMessageHeader {
id: messageHeader
width: parent.width
displayName: messageDetails.displayName
secondaryName: messageDetails.secondaryName
tertiaryDetail: messageDetails.chatID
isMutualContact: messageDetails.isMutualContact
trustIndicator: messageDetails.trustIndicator
resendText: statusMessage.resendText
showResendButton: messageDetails.hasExpired && messageDetails.amISender
onClicked: statusMessage.senderNameClicked()
onResendClicked: statusMessage.resendClicked()
visible: !editMode
Layout.fillWidth: true
sender: root.messageDetails.sender
amISender: root.messageDetails.amISender
messageOriginInfo: root.messageDetails.messageOriginInfo
resendText: root.resendText
showResendButton: root.hasExpired && root.messageDetails.amISender
onClicked: root.senderNameClicked(sender, mouse)
onResendClicked: root.resendClicked()
visible: root.showHeader && !editMode
timestamp.text: root.timestampString
timestamp.tooltip.text: root.timestampTooltipString
displayNameClickable: root.profileClickable
}
Loader {
active: !editMode && !!messageDetails.messageText
width: parent.width
Layout.fillWidth: true
active: !editMode && !!root.messageDetails.messageText
visible: active
sourceComponent: StatusTextMessage {
width: parent.width
textField.text: messageDetails.messageText
objectName: "StatusMessage_textMessage"
textField.text: {
if (root.messageDetails.contentType === StatusMessage.ContentType.Sticker)
return "";
const formattedMessage = Utils.linkifyAndXSS(root.messageDetails.messageText);
if (root.messageDetails.contentType === StatusMessage.ContentType.Emoji)
return Emoji.parse(formattedMessage, Emoji.size.middle, Emoji.format.png);
if (root.isEdited) {
const index = formattedMessage.endsWith("code>") ? formattedMessage.length : formattedMessage.length - 4;
const editedMessage = formattedMessage.slice(0, index)
+ ` <span class="isEdited">` + qsTr("(edited)") + `</span>`
+ formattedMessage.slice(index);
return Utils.getMessageWithStyle(Emoji.parse(editedMessage), textField.hoveredLink)
}
return Utils.getMessageWithStyle(Emoji.parse(formattedMessage), textField.hoveredLink)
}
onLinkActivated: {
root.linkActivated(link);
}
}
}
Loader {
active: messageDetails.contentType === StatusMessage.ContentType.Image && !editMode
active: root.messageDetails.contentType === StatusMessage.ContentType.Image && !editMode
visible: active
sourceComponent: StatusImageMessage {
source: messageDetails.contentType === StatusMessage.ContentType.Image ? messageDetails.messageContent : ""
onClicked: statusMessage.imageClicked()
shapeType: messageDetails.amISender ? StatusImageMessage.ShapeType.RIGHT_ROUNDED : StatusImageMessage.ShapeType.LEFT_ROUNDED
source: root.messageDetails.contentType === StatusMessage.ContentType.Image ? root.messageDetails.messageContent : ""
onClicked: root.imageClicked(image, mouse, imageSource)
shapeType: root.messageDetails.amISender ? StatusImageMessage.ShapeType.RIGHT_ROUNDED : StatusImageMessage.ShapeType.LEFT_ROUNDED
}
}
StatusSticker {
visible: messageDetails.contentType === StatusMessage.ContentType.Sticker && !editMode
image.source: messageDetails.messageContent
onLoaded: statusMessage.stickerLoaded()
Loader {
active: root.messageDetails.contentType === StatusMessage.ContentType.Sticker && !editMode
visible: active
sourceComponent: StatusSticker {
asset.isImage: true
asset.name: root.messageDetails.messageContent
onLoaded: root.stickerLoaded()
onClicked: {
root.stickerClicked()
}
}
}
Loader {
active: messageDetails.contentType === StatusMessage.ContentType.Audio && !editMode
active: root.messageDetails.contentType === StatusMessage.ContentType.Audio && !editMode
visible: active
sourceComponent: StatusAudioMessage {
audioSource: messageDetails.messageContent
audioSource: root.messageDetails.messageContent
hovered: hoverHandler.hovered
audioMessageInfoText: statusMessage.audioMessageInfoText
audioMessageInfoText: root.audioMessageInfoText
}
}
Loader {
id: linksLoader
active: !!linksLoader.sourceComponent
active: !root.editMode
visible: active
}
Loader {
id: transactionBubbleLoader
active: messageDetails.contentType === StatusMessage.ContentType.Transaction && !editMode
active: root.messageDetails.contentType === StatusMessage.ContentType.Transaction && !editMode
visible: active
}
Loader {
id: invitationBubbleLoader
active: messageDetails.contentType === StatusMessage.ContentType.Invitation && !editMode
active: root.messageDetails.contentType === StatusMessage.ContentType.Invitation && !editMode
visible: active
}
StatusEditMessage {
id: editComponent
width: parent.width
msgText: messageDetails.messageText
visible: editMode
saveButtonText: statusMessage.saveButtonText
cancelButtonText: statusMessage.cancelButtonText
onCancelEditClicked: editMode = false
onEditCompleted: {
editMode = false
statusMessage.editCompleted(newMsgText)
}
Layout.fillWidth: true
Layout.rightMargin: 16
active: root.editMode
visible: active
msgText: root.messageDetails.messageText
saveButtonText: root.saveButtonText
cancelButtonText: root.cancelButtonText
onEditCancelled: root.editCancelled()
onEditCompleted: root.editCompleted(newMsgText)
}
StatusBaseText {
id: retryLbl
color: Theme.palette.dangerColor1
text: statusMessage.resendText
text: root.resendText
font.pixelSize: 12
visible: messageDetails.hasExpired && messageDetails.amISender && !messageDetails.timestamp && !editMode
visible: root.hasExpired && root.messageDetails.amISender && !root.timestamp && !editMode
MouseArea {
cursorShape: Qt.PointingHandCursor
anchors.fill: parent
onClicked: statusMessage.resendClicked()
onClicked: root.resendClicked()
}
}
Loader {
id: footer
active: sourceComponent && !editMode
active: root.reactionsModel.count > 0
visible: active
sourceComponent: StatusMessageEmojiReactions {
id: emojiReactionsPanel
emojiReactionsModel: root.reactionsModel
store: root.messageStore
icons: root.reactionIcons
onHoverChanged: {
root.hoverChanged(messageId, hovered)
}
isCurrentUser: root.messageDetails.amISender
onAddEmojiClicked: root.addReactionClicked(sender, mouse)
onToggleReaction: root.toggleReactionClicked(emojiID)
}
}
}
}
@@ -195,6 +404,6 @@ Rectangle {
anchors.rightMargin: 20
anchors.top: parent.top
anchors.topMargin: -8
visible: hoverHandler.hovered && !editMode
visible: hoverHandler.hovered && !root.hideQuickActions
}
}
@@ -6,24 +6,10 @@ QtObject {
id: msgDetails
property bool amISender: false
property string displayName: ""
property string secondaryName: ""
property string chatID: ""
property StatusImageSettings profileImage: StatusImageSettings {
width: 40
height: 40
}
property StatusMessageSenderDetails sender: StatusMessageSenderDetails { }
property bool isEdited: false
property string messageText: ""
property int contentType: 0
property string messageText: ""
property string messageContent: ""
property bool isMutualContact: false
property var trustIndicator: StatusContactVerificationIcons.TrustedType.None
property bool hasMention: false
property bool isPinned: false
property string pinnedBy: ""
property bool hasExpired: false
property string timestamp: ""
property string messageOriginInfo: ""
}
@@ -0,0 +1,33 @@
import QtQuick 2.0
import StatusQ.Core 0.1
QtObject {
id: root
property string id: ""
property string userName: ""
property string ensName: ""
property string localName: ""
property bool isContact: false
property int trustIndicator: StatusContactVerificationIcons.TrustedType.None
property StatusProfileImageSettings profileImage: StatusProfileImageSettings {
pubkey: root.id
showRing: !root.ensName
width: 40
height: 40
}
readonly property string displayName: root.localName !== ""
? root.localName
: root.ensName !== ""
? root.ensName
: root.userName
readonly property string secondaryName: root.localName === ""
? ""
: root.ensName !== ""
? root.ensName
: root.userName
}
@@ -12,9 +12,9 @@ StatusListItem {
implicitWidth: 286
implicitHeight: 48
icon.background.width: 20
icon.background.height: 20
icon.background.color: "transparent"
asset.bgWidth: 20
asset.bgHeight: 20
asset.bgColor: "transparent"
statusListItemIcon.anchors.topMargin: 14
+13 -15
View File
@@ -5,33 +5,31 @@ import StatusQ.Core.Theme 0.1
Rectangle {
id: statusRoundedIcon
property StatusIconSettings icon: StatusIconSettings {
property StatusAssetSettings asset: StatusAssetSettings {
width: 24
height: 24
rotation: 0
color: Theme.palette.primaryColor1
background: StatusIconBackgroundSettings {
width: 40
height: 40
color: Theme.palette.primaryColor3
}
bgWidth: 40
bgHeight: 40
bgColor: Theme.palette.primaryColor3
}
color: icon.background.color
implicitWidth: icon.background.width
implicitHeight: icon.background.height
radius: icon.background.width / 2
color: asset.bgColor
implicitWidth: asset.bgWidth
implicitHeight: asset.bgHeight
radius: asset.bgWidth / 2
StatusIcon {
id: statusIcon
anchors.centerIn: parent
width: statusRoundedIcon.icon.width
height: statusRoundedIcon.icon.height
width: statusRoundedIcon.asset.width
height: statusRoundedIcon.asset.height
color: statusRoundedIcon.icon.color
icon: statusRoundedIcon.icon.name
rotation: statusRoundedIcon.icon.rotation
color: statusRoundedIcon.asset.color
icon: statusRoundedIcon.asset.name
rotation: statusRoundedIcon.asset.rotation
}
}
+36 -40
View File
@@ -4,7 +4,7 @@ import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
Loader {
id: statusSmartIdenticon
id: root
property string name: ""
property int dZ: 100
@@ -12,51 +12,46 @@ Loader {
// Badge color properties must be set if badgeItem.visible = true
property alias badge: statusBadge
property StatusIconSettings icon: StatusIconSettings {
width: 40
height: 40
}
property StatusImageSettings image: StatusImageSettings {
property StatusAssetSettings asset: StatusAssetSettings {
width: 40
height: 40
}
property StatusIdenticonRingSettings ringSettings: StatusIdenticonRingSettings {
initalAngleRad: 0
ringPxSize: Math.max(1.5, statusSmartIdenticon.image.width / 24.0)
ringPxSize: Math.max(1.5, root.asset.width/ 24.0)
distinctiveColors: Theme.palette.identiconRingColors
}
sourceComponent: statusSmartIdenticon.icon.isLetterIdenticon ? letterIdenticon :
!!statusSmartIdenticon.image.source.toString() ? roundedImage :
!!statusSmartIdenticon.icon.name.toString() ? roundedIcon : letterIdenticon
sourceComponent: (root.asset.isLetterIdenticon || root.asset.name === "") ? letterIdenticon :
!root.asset.isImage ? roundedIcon : roundedImage
Component {
id: roundedImage
Item {
width: statusSmartIdenticon.image.width
height: statusSmartIdenticon.image.height
width: root.asset.width
height: root.asset.height
StatusRoundedImage {
id: statusRoundImage
width: parent.width
height: parent.height
image.source: statusSmartIdenticon.image.source
image.source: root.asset.name
showLoadingIndicator: true
border.width: statusSmartIdenticon.image.isIdenticon ? 1 : 0
border.width: root.asset.imgIsIdenticon ? 1 : 0
border.color: Theme.palette.directColor7
color: statusSmartIdenticon.image.isIdenticon ?
color: root.asset.imgIsIdenticon ?
Theme.palette.statusRoundedImage.backgroundColor :
"transparent"
}
Loader {
anchors.centerIn: parent
active: statusRoundImage.image.status === Image.Error
active: root.asset.imgStatus === Image.Error ||
statusRoundImage.image.status === Image.Error
sourceComponent: letterIdenticon
onLoaded: {
item.color = Theme.palette.miscColor5
item.width = statusSmartIdenticon.image.width
item.height = statusSmartIdenticon.image.height
item.width = root.asset.width
item.height = root.asset.height
}
}
}
@@ -65,47 +60,48 @@ Loader {
Component {
id: roundedIcon
StatusRoundIcon {
icon.background.width: statusSmartIdenticon.icon.background.width
icon.background.height: statusSmartIdenticon.icon.background.height
icon.background.color: statusSmartIdenticon.icon.background.color
icon.width: statusSmartIdenticon.icon.width
icon.height: statusSmartIdenticon.icon.height
icon.name: statusSmartIdenticon.icon.name
icon.rotation: statusSmartIdenticon.icon.rotation
icon.color: statusSmartIdenticon.icon.color
asset.bgWidth: root.asset.bgWidth
asset.bgHeight: root.asset.bgHeight
asset.bgColor: root.asset.bgColor
asset.width: root.asset.width
asset.height: root.asset.height
asset.name: root.asset.name
asset.rotation: root.asset.rotation
asset.color: root.asset.color
}
}
Component {
id: letterIdenticon
StatusLetterIdenticon {
width: statusSmartIdenticon.icon.width
height: statusSmartIdenticon.icon.height
color: statusSmartIdenticon.icon.color
name: statusSmartIdenticon.name
emoji: statusSmartIdenticon.icon.emoji
emojiSize: statusSmartIdenticon.icon.emojiSize
letterSize: statusSmartIdenticon.icon.letterSize
charactersLen: statusSmartIdenticon.icon.charactersLen
objectName: "statusSmartIdenticonLetter"
width: root.asset.width
height: root.asset.height
color: root.asset.color
name: root.name
emoji: root.asset.emoji
emojiSize: root.asset.emojiSize
letterSize: root.asset.letterSize
charactersLen: root.asset.charactersLen
}
}
// Next components are painted above main sourceComponent
StatusIdenticonRing {
settings: statusSmartIdenticon.ringSettings
settings: root.ringSettings
anchors.fill: parent
z: statusSmartIdenticon.dZ/2
z: root.dZ/2
}
// State component
StatusBadge {
id: statusBadge
visible: false
anchors.bottom: statusSmartIdenticon.bottom
anchors.right: statusSmartIdenticon.right
anchors.bottom: root.bottom
anchors.right: root.right
border.width: 3
implicitHeight: 15
implicitWidth: 15
z: statusSmartIdenticon.dZ
z: root.dZ
}
}
+14 -7
View File
@@ -177,9 +177,10 @@ Item {
"localNickname": entry.localNickname,
"isVerified": entry.isVerified,
"isUntrustworthy": entry.isUntrustworthy,
"isContact": entry.isMutualContact,
"isContact": entry.isContact,
"ringSpecModel": entry.ringSpecModel,
"icon": entry.icon,
"isImage": entry.isImage,
"onlineStatus": entry.onlineStatus,
"tagIcon": entry.tagIcon ? entry.tagIcon : "",
"isReadonly": !!entry.isReadonly});
@@ -216,7 +217,7 @@ Item {
if(root.orderByReadonly) {
for(var i = 0; i < namesModel.count; i++) {
var entry = namesModel.get(i)
if(entry.isReadonly) {
if(entry.tagIcon === "crown") {
namesModel.move(i, 0, 1)
}
}
@@ -247,6 +248,7 @@ Item {
StatusBaseText {
Layout.preferredWidth: 22
Layout.alignment: Qt.AlignVCenter
font.pixelSize: 15
color: Theme.palette.baseColor1
text: root.toLabelText
visible: (parent.width>22)
@@ -304,8 +306,11 @@ Item {
if ((event.key === Qt.Key_Backspace || event.key === Qt.Key_Escape)
&& getText(cursorPosition, (cursorPosition-1)) === ""
&& (namesList.count-1) >= 0) {
removeMember(namesModel.get(namesList.count-1).pubKey);
namesModel.remove((namesList.count-1), 1);
const item = namesModel.get(namesList.count-1)
if (!item.isReadonly) {
removeMember(item.pubKey);
namesModel.remove((namesList.count-1), 1);
}
}
if ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && (sortedList.count > 0)) {
root.insertTag(sortedList.get(userListView.currentIndex).name,
@@ -377,6 +382,7 @@ Item {
}
contentItem: ListView {
id: userListView
objectName: "tagSelectorUserList"
anchors {
fill: parent
topMargin: 16
@@ -410,9 +416,10 @@ Item {
isVerified: model.isVerified
isUntrustworthy: model.isUntrustworthy
isContact: model.isContact
image.source: model.icon
image.isIdenticon: false
icon.color: Theme.palette.userCustomizationColors[root.colorIdForPubkeyGetter(model.pubKey)]
asset.name: model.icon
asset.color: Theme.palette.userCustomizationColors[root.colorIdForPubkeyGetter(model.pubKey)]
asset.isImage: (asset.name !== "")
asset.isLetterIdenticon: (asset.name === "")
status: model.onlineStatus
statusListItemIcon.badge.border.color: sensor.containsMouse ? Theme.palette.baseColor2 : Theme.palette.baseColor4
ringSettings.ringSpecModel: root.ringSpecModelGetter(model.pubKey)
+10 -2
View File
@@ -75,10 +75,10 @@ Control {
property int duration: 0
/*!
\qmlproperty StatusIconSettings StatusToastMessage::icon
\qmlproperty StatusAssetSettings StatusToastMessage::icon
This property holds a set of settings for the icon of the ToastMessage.
*/
property StatusIconSettings icon: StatusIconSettings {
property StatusAssetSettings icon: StatusAssetSettings {
width: 23
height: 23
}
@@ -125,6 +125,11 @@ Control {
root.open = true;
}
/*!
\qmlsignal
This signal is emitted when the ToastMessage is clicked.
*/
signal clicked()
/*!
\qmlsignal
This signal is emitted when the ToastMessage is closed (after animation).
@@ -214,6 +219,9 @@ Control {
onMouseXChanged: {
root.open = (mouseX < (root.width/3));
}
onClicked: {
root.clicked();
}
}
RowLayout {
anchors.fill: parent
+44
View File
@@ -0,0 +1,44 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.13
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
ToolBar {
id: root
property int notificationCount: 0
property Item headerContent
property alias notificationButton: notificationButton
signal notificationButtonClicked()
implicitWidth: visible ? 518 : 0
implicitHeight: visible ? 60 : 0
padding: 8
background: null
RowLayout {
anchors.fill: parent
spacing: 0
Control {
id: headerContentItem
Layout.fillWidth: !!headerContent
Layout.fillHeight: !!headerContent
background: null
contentItem: (!!headerContent) ? headerContent : null
}
Item {
Layout.fillWidth: !headerContent
}
StatusActivityCenterButton {
id: notificationButton
unreadNotificationsCount: root.notificationCount
onClicked: root.notificationButtonClicked()
}
}
}

Some files were not shown because too many files have changed in this diff Show More