Merge lp:~renatofilho/address-book-app/new-bottom-edge into lp:address-book-app
- new-bottom-edge
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Bill Filler |
Approved revision: | 596 |
Merged at revision: | 528 |
Proposed branch: | lp:~renatofilho/address-book-app/new-bottom-edge |
Merge into: | lp:address-book-app |
Prerequisite: | lp:~renatofilho/address-book-app/keyboard-navigation |
Diff against target: |
2821 lines (+809/-955) 37 files modified
CMakeLists.txt (+11/-0) config.h.in (+1/-0) debian/control (+1/-0) src/app/addressbookapp.cpp (+5/-39) src/app/addressbookapp.h (+0/-6) src/imports/ABContactEditorPage.qml (+21/-18) src/imports/ABContactListPage.qml (+251/-356) src/imports/ABContactViewPage.qml (+57/-28) src/imports/ABEmptyState.qml (+61/-0) src/imports/ABMultiColumnEmptyState.qml (+75/-0) src/imports/ABNewContactBottomEdge.qml (+89/-0) src/imports/BottomEdge.qml (+0/-338) src/imports/BottomEdgeShadow.qml (+0/-31) src/imports/CMakeLists.txt (+3/-2) src/imports/MainWindow.qml (+42/-21) src/imports/Settings/SettingsPage.qml (+3/-3) src/imports/Ubuntu/AddressBook/Base/ContactDetailGroupBase.qml (+4/-5) src/imports/Ubuntu/AddressBook/Base/KeyboardRectangle.qml (+4/-1) src/imports/Ubuntu/AddressBook/ContactEditor/ComboButtonAddField.qml (+2/-2) src/imports/Ubuntu/AddressBook/ContactEditor/ContactDetailAvatarEditor.qml (+0/-1) src/imports/Ubuntu/AddressBook/ContactEditor/ContactDetailGroupWithTypeEditor.qml (+0/-1) src/imports/Ubuntu/AddressBook/ContactEditor/ContactDetailWithTypeEditor.qml (+1/-1) src/imports/Ubuntu/AddressBook/ContactEditor/ContactEditorPage.qml (+74/-18) src/imports/Ubuntu/AddressBook/ContactEditor/TextInputDetail.qml (+6/-15) src/imports/Ubuntu/AddressBook/ContactShare/ContactSharePage.qml (+10/-2) src/imports/Ubuntu/AddressBook/ContactView/ContactViewPage.qml (+13/-2) src/imports/Ubuntu/Contacts/ContactListView.qml (+15/-18) src/imports/Ubuntu/Contacts/ContactSimpleListView.qml (+3/-3) src/imports/Ubuntu/Contacts/ListItemWithActions.qml (+19/-0) tests/autopilot/address_book_app/__init__.py (+28/-10) tests/autopilot/address_book_app/pages/_ab_contact_list_page.py (+1/-19) tests/autopilot/address_book_app/tests/test_add_contact.py (+1/-3) tests/autopilot/address_book_app/tests/test_create_new_from_uri.py (+0/-2) tests/autopilot/address_book_app/tests/test_edit_contact.py (+2/-4) tests/autopilot/address_book_app/tests/test_import_vcard.py (+1/-1) tests/autopilot/address_book_app/tests/test_single_pick_mode.py (+1/-0) tests/qml/tst_ContactPreviewPage.qml (+4/-5) |
To merge this branch: | bzr merge lp:~renatofilho/address-book-app/new-bottom-edge |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Bill Filler (community) | Approve | ||
PS Jenkins bot | continuous-integration | Needs Fixing | |
Review via email: mp+279613@code.launchpad.net |
This proposal supersedes a proposal from 2015-12-04.
Commit message
Implement the new bottom edge using the SDK component.
Description of the change
PS Jenkins bot (ps-jenkins) wrote : | # |
- 548. By Renato Araujo Oliveira Filho
-
Update BottomEdge editor page with the correct contact model.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:548
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 549. By Renato Araujo Oliveira Filho
-
Removed support for deprecated application arguments.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:549
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 550. By Renato Araujo Oliveira Filho
-
Make use of the new SDK PageHearder API.
- 551. By Renato Araujo Oliveira Filho
-
WORKAROUND: Set 'QuickUtils.
mouseAttached = true' to avoid problems with bottom edge on desktop; - 552. By Renato Araujo Oliveira Filho
-
Make sure that a contact is selected on application startup.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:551
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:552
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 553. By Renato Araujo Oliveira Filho
-
Push contact view page component instead of object to avoid problems with page stack.
- 554. By Renato Araujo Oliveira Filho
-
Make bottom edge component on contact view available only when in dual column layout.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:554
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 555. By Renato Araujo Oliveira Filho
-
Does not use navigationActions.
- 556. By Renato Araujo Oliveira Filho
-
Trunk merged.
- 557. By Renato Araujo Oliveira Filho
-
Fix problems with previous merge.
- 558. By Renato Araujo Oliveira Filho
-
Remove debug message.
Fix focus on contact list after close contact editor page.
Fix ambigous 'esc' short cut when editor page is opened.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:558
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 559. By Renato Araujo Oliveira Filho
-
Create a empty state page for multi column layout.
- 560. By Renato Araujo Oliveira Filho
-
Move focus back to contaclist after close ContactEditor page.
Add 'esc' shortcut to close BottomEdge.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:559
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:560
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 561. By Renato Araujo Oliveira Filho
-
Change bottom edge visual if a mouse is present.
- 562. By Renato Araujo Oliveira Filho
-
Update test to use new header API.
- 563. By Renato Araujo Oliveira Filho
-
Trunk merged.
- 564. By Renato Araujo Oliveira Filho
-
Create a leading actions property on Contact editor page to avoid problems with SDK replacing it.
Check if the mouse event is a real mouse event and not a touch event. - 565. By Renato Araujo Oliveira Filho
-
Only enable keyboard visuals after pres 'down' key. To avoid enabling it while using the virtual keyboard.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:564
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:565
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 566. By Renato Araujo Oliveira Filho
-
Sync load bottom edge page.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:566
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 567. By Renato Araujo Oliveira Filho
-
Load BottomEdge component async to avoid delays on app startup.
Fix bottom edge contents size. - 568. By Renato Araujo Oliveira Filho
-
Does not move contact list when vkb appears on bottom edge page.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:567
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:568
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 569. By Renato Araujo Oliveira Filho
-
Trunk merged.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:569
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Bill Filler (bfiller) wrote : | # |
Silo 55:
tesing on krillin
- try to search, type in search string, open resultant contact, click back, now you are stuck on search page with back button disabled
See this in log
file://
file://
- opening a contact, sometimes get a page with no back button, it's happend 3 or 4 times but can't reproduce reliably
- the order of the icons changed on the toolbar, settings and search positions are swapped
- Very often bottom edge swipe fails and it does not get properly activated (doesn't get displayed), when this happens I see multiple failure messages:
file://
- There is a very big delay in the animation when swiping up from bottom, the page does not follow my finger as it used to. We had this problem in the past and needed to have the page created up front as it takes too long to create it dynamically. This shouldn't be done at start up but after the app is displayed then it should be created and cached.
- Open bottom edge, then close it, get these errors in log
file://
file://
file://
file://
- pressing edit on a contact is slow again
- I see multiple of these errors everytime trying to edit a contact
file://
- 570. By Renato Araujo Oliveira Filho
-
Fixed 'back' action state while searching.
- 571. By Renato Araujo Oliveira Filho
-
Compile ContactEditorPage before push it on stack.
- 572. By Renato Araujo Oliveira Filho
-
Avoid stole contact list focus while creating bottom edge component.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:572
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Renato Araujo Oliveira Filho (renatofilho) wrote : | # |
> Silo 55:
> tesing on krillin
>
> - try to search, type in search string, open resultant contact, click back,
> now you are stuck on search page with back button disabled
> See this in log
> file://
> TypeError: Cannot read property 'status' of null
> file://
> TypeError: Cannot read property 'status' of null
Fixed rev. 50
>
> - opening a contact, sometimes get a page with no back button, it's happend 3
> or 4 times but can't reproduce reliably
>
> - the order of the icons changed on the toolbar, settings and search positions
> are swapped
This is a regression caused by the new SDK, we need to discuss if it was intentional and we need to change the code or it was a real bug.
>
> - Very often bottom edge swipe fails and it does not get properly activated
> (doesn't get displayed), when this happens I see multiple failure messages:
> file://
> gnueabihf/
> to get image from provider: image:/
This warning message is a bug caused by the new SDK, you can notice that now the input fields does not have the clear button anymore. You should have the same problems in all apps.
>
> - There is a very big delay in the animation when swiping up from bottom, the
> page does not follow my finger as it used to. We had this problem in the past
> and needed to have the page created up front as it takes too long to create it
> dynamically. This shouldn't be done at start up but after the app is displayed
> then it should be created and cached.
Everything on bottom edge is controlled by the SDK now, we (the application) doe not have control over the animation or how to load the page. During the tests I noticed that the page does not follow the finger speed but I think it is intentional because the animation has a controlled speed. (we can discuss that with the SDK team).
>
> - Open bottom edge, then close it, get these errors in log
> file://
> gnueabihf/
> to get image from provider: image:/
> file://
> gnueabihf/
> to get image from provider: image:/
> file://
> gnueabihf/
> to get image from provider: image:/
> file://
> gnueabihf/
> to get image from provider: image:/
This warning message is a bug caused by the new SDK, you can notice that now the input fields does not have the clear button anymore. You should have the same problems in all apps.
>
> - pressing edit on a contact is slow again
I have optimized it a lit bit on rev 573. But we can not create the page sync as we use to do because of this bug #1528017.
AdaptativeLayout always create the page async and for some reason it is way more slower t...
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:573
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 573. By Renato Araujo Oliveira Filho
-
Disable edit button after first click on it. (avoid push the page more than once)
- 574. By Renato Araujo Oliveira Filho
-
highlight contact on click.
- 575. By Renato Araujo Oliveira Filho
-
Quick focus on contact name after open bottom edge page.
- 576. By Renato Araujo Oliveira Filho
-
Does not highlight settings item if not using keyboard.
- 577. By Renato Araujo Oliveira Filho
-
Update autopilot tests to work with the new bottom edge component.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:576
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 578. By Renato Araujo Oliveira Filho
-
Removed debug message.
- 579. By Renato Araujo Oliveira Filho
-
Disable bottom edge while searching on multi colum layout.
- 580. By Renato Araujo Oliveira Filho
-
Cancel search after open bottom edge.
- 581. By Renato Araujo Oliveira Filho
-
Update contact view title on contact name change.
- 582. By Renato Araujo Oliveira Filho
-
Removed debug message.
- 583. By Renato Araujo Oliveira Filho
-
Fetch selected contact on application expansion.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:577
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:583
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 584. By Renato Araujo Oliveira Filho
-
Use unity 8 private api to detect mouse and keyboard.
- 585. By Renato Araujo Oliveira Filho
-
Fetch first contact if no contact is selected after close bottom edge.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:585
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 586. By Renato Araujo Oliveira Filho
-
Fixed field focus while adding new fields on contact editor.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:586
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 587. By Renato Araujo Oliveira Filho
-
Disable bottom edge shortcut on contact list while it is not active.
- 588. By Renato Araujo Oliveira Filho
-
Update autopilot tests to work with the new bottom edge components.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:588
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 589. By Renato Araujo Oliveira Filho
-
Update contact delegate click animation.
- 590. By Renato Araujo Oliveira Filho
-
Remove unused variables.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:590
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 591. By Renato Araujo Oliveira Filho
-
Fixed focus on wrong field after add a new contact detail
- 592. By Renato Araujo Oliveira Filho
-
Focus contact list after close bottom edge.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:592
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 593. By Renato Araujo Oliveira Filho
-
set minimum width and height for the app.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:593
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 594. By Renato Araujo Oliveira Filho
-
Fixed focus on contact deletion.
- 595. By Renato Araujo Oliveira Filho
-
Fixed share component page to work with pagestack
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:595
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 596. By Renato Araujo Oliveira Filho
-
Reduce the application width necessary to change into multi column layout.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:596
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Bill Filler (bfiller) wrote : | # |
All outstanding issues resolved
Preview Diff
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2015-09-03 17:15:32 +0000 |
3 | +++ CMakeLists.txt 2016-01-07 13:19:12 +0000 |
4 | @@ -83,6 +83,17 @@ |
5 | set(ADDRESS_BOOK_APP_DESKTOP_FILE address-book-app.desktop) |
6 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall") |
7 | |
8 | +#find unity8 qml libraries |
9 | +find_path(LIB_UNITY_QML_EXISTS NAMES libUnity-qml.so |
10 | + HINTS "/usr/lib/x86_64-linux-gnu/unity8/qml/Unity/" |
11 | + NO_CMAKE_PATH |
12 | + NO_CMAKE_ENVIRONMENT_PATH |
13 | + NO_SYSTEM_ENVIRONMENT_PATH |
14 | +) |
15 | +if(!LIB_UNITY_QML_EXISTS) |
16 | + MESSAGE(FATAL_ERROR "unity8 private package not-found") |
17 | +endif() |
18 | + |
19 | add_subdirectory(data) |
20 | add_subdirectory(src) |
21 | add_subdirectory(po) |
22 | |
23 | === modified file 'config.h.in' |
24 | --- config.h.in 2015-09-29 19:03:44 +0000 |
25 | +++ config.h.in 2016-01-07 13:19:12 +0000 |
26 | @@ -10,6 +10,7 @@ |
27 | #define QT_EXTRA_IMPORTS_DIR "@QT_EXTRA_IMPORTS_DIR@" |
28 | #define ADDRESS_BOOK_APP_CLICK_PACKAGE "@CLICK_MODE@" |
29 | #define I18N_DIRECTORY "@CMAKE_INSTALL_PREFIX@/share/locale" |
30 | +#define UNITY8_QML_PATH "/usr/lib/@CMAKE_C_LIBRARY_ARCHITECTURE@/unity8/qml/" |
31 | |
32 | #define SETTINGS_ORGANIZATION_NAME "com.ubuntu.address-book" |
33 | #define SETTINGS_ORGANIZATION_DOMAIN "canonical.com" |
34 | |
35 | === modified file 'debian/control' |
36 | --- debian/control 2015-10-16 13:37:25 +0000 |
37 | +++ debian/control 2016-01-07 13:19:12 +0000 |
38 | @@ -52,6 +52,7 @@ |
39 | qtdeclarative5-ubuntu-history0.1, |
40 | qtdeclarative5-ubuntu-keyboard-extensions0.1, |
41 | qtdeclarative5-ubuntu-telephony-phonenumber0.1 (>= 0.1+14.10.20140715.1), |
42 | + unity8-private, |
43 | ${misc:Depends}, |
44 | ${shlibs:Depends}, |
45 | Description: Address Book application |
46 | |
47 | === modified file 'src/app/addressbookapp.cpp' |
48 | --- src/app/addressbookapp.cpp 2015-12-18 13:48:47 +0000 |
49 | +++ src/app/addressbookapp.cpp 2016-01-07 13:19:12 +0000 |
50 | @@ -44,8 +44,6 @@ |
51 | { |
52 | qDebug() << "usage:" |
53 | << arguments.at(0).toUtf8().constData() |
54 | - << "[addressbook:///addphone?id=<contact-id>&phone=<phone-number>]" |
55 | - << "[addressbook:///addnewphone?phone=<phone-number>]" |
56 | << "[addressbook:///contact?id=<contact-id>]" |
57 | << "[addressbook:///create?phone=<phone-number>]" |
58 | << "[addressbook:///pick?single=<true/false>]" |
59 | @@ -104,8 +102,7 @@ |
60 | m_netManager(new QNetworkConfigurationManager), |
61 | m_pickingMode(false), |
62 | m_testMode(false), |
63 | - m_withArgs(false), |
64 | - m_withKeyboard(false) |
65 | + m_withArgs(false) |
66 | { |
67 | s_elapsed.start(); |
68 | setOrganizationName(SETTINGS_ORGANIZATION_NAME); |
69 | @@ -194,10 +191,13 @@ |
70 | this, SLOT(onViewStatusChanged(QQuickView::Status))); |
71 | QObject::connect(m_view->engine(), SIGNAL(quit()), SLOT(quit())); |
72 | |
73 | + m_view->setMinimumWidth(300); |
74 | + m_view->setMinimumHeight(500); |
75 | m_view->setResizeMode(QQuickView::SizeRootObjectToView); |
76 | m_view->setTitle("AddressBook"); |
77 | qDebug() << "New import path:" << QCoreApplication::applicationDirPath() + "/" + importPath(""); |
78 | m_view->engine()->addImportPath(QCoreApplication::applicationDirPath() + "/" + importPath("")); |
79 | + m_view->engine()->addImportPath(UNITY8_QML_PATH); |
80 | m_view->rootContext()->setContextProperty("QTCONTACTS_MANAGER_OVERRIDE", defaultManager); |
81 | m_view->rootContext()->setContextProperty("application", this); |
82 | m_view->rootContext()->setContextProperty("contactKey", contactKey); |
83 | @@ -318,17 +318,12 @@ |
84 | |
85 | if (methodsMetaData.isEmpty()) { |
86 | QStringList args; |
87 | - //edit |
88 | - args << "id" << "phone"; |
89 | - methodsMetaData.insert("addphone", args); |
90 | - args.clear(); |
91 | - |
92 | //view |
93 | args << "id"; |
94 | methodsMetaData.insert("contact", args); |
95 | args.clear(); |
96 | |
97 | - //add |
98 | + //create |
99 | args << "phone"; |
100 | methodsMetaData.insert("create", args); |
101 | args.clear(); |
102 | @@ -342,11 +337,6 @@ |
103 | args << "url"; |
104 | methodsMetaData.insert("importvcard", args); |
105 | args.clear(); |
106 | - |
107 | - //addnewphone |
108 | - args << "phone"; |
109 | - methodsMetaData.insert("addnewphone", args); |
110 | - args.clear(); |
111 | } |
112 | |
113 | QUrlQuery query(url); |
114 | @@ -448,26 +438,6 @@ |
115 | qDebug() << "ELAPSED:" << s_elapsed.elapsed() / 1000.0; |
116 | } |
117 | |
118 | -bool AddressBookApp::notify(QObject *obj, QEvent *event) |
119 | -{ |
120 | - switch(event->type()) |
121 | - { |
122 | - case QEvent::KeyPress: |
123 | - // we have no way to detect when a physical keyboard is connected, so we |
124 | - // assume there is one when the down key is pressed |
125 | - if (!m_withKeyboard && (static_cast<QKeyEvent*>(event)->key() == Qt::Key_Down)) { |
126 | - m_withKeyboard = true; |
127 | - Q_EMIT usingKeyboardChanged(); |
128 | - return false; |
129 | - } |
130 | - break; |
131 | - default: |
132 | - break; |
133 | - } |
134 | - |
135 | - return QGuiApplication::notify(obj, event); |
136 | -} |
137 | - |
138 | QString AddressBookApp::callbackApplication() const |
139 | { |
140 | return m_callbackApplication; |
141 | @@ -497,7 +467,3 @@ |
142 | return !m_updateWatcher.isNull(); |
143 | } |
144 | |
145 | -bool AddressBookApp::usingKeyboard() const |
146 | -{ |
147 | - return m_withKeyboard; |
148 | -} |
149 | |
150 | === modified file 'src/app/addressbookapp.h' |
151 | --- src/app/addressbookapp.h 2015-12-16 18:35:33 +0000 |
152 | +++ src/app/addressbookapp.h 2016-01-07 13:19:12 +0000 |
153 | @@ -32,7 +32,6 @@ |
154 | Q_PROPERTY(bool isOnline READ isOnline NOTIFY isOnlineChanged) |
155 | Q_PROPERTY(bool serverSafeMode READ serverSafeMode NOTIFY serverSafeModeChanged) |
156 | Q_PROPERTY(bool updating READ updating NOTIFY updatingChanged) |
157 | - Q_PROPERTY(bool usingKeyboard READ usingKeyboard NOTIFY usingKeyboardChanged) |
158 | |
159 | public: |
160 | AddressBookApp(int &argc, char **argv); |
161 | @@ -46,14 +45,12 @@ |
162 | bool isOnline() const; |
163 | bool serverSafeMode() const; |
164 | bool updating() const; |
165 | - bool usingKeyboard() const; |
166 | |
167 | Q_SIGNALS: |
168 | void callbackApplicationChanged(); |
169 | void isOnlineChanged(); |
170 | void serverSafeModeChanged(); |
171 | void updatingChanged(); |
172 | - void usingKeyboardChanged(); |
173 | void sourcesChanged(); |
174 | |
175 | public Q_SLOTS: |
176 | @@ -69,8 +66,6 @@ |
177 | // debug |
178 | void elapsed() const; |
179 | |
180 | -protected: |
181 | - bool notify(QObject *obj, QEvent *event); |
182 | |
183 | private Q_SLOTS: |
184 | void onUpdateCallFinished(QDBusPendingCallWatcher *watcher); |
185 | @@ -90,7 +85,6 @@ |
186 | bool m_pickingMode; |
187 | bool m_testMode; |
188 | bool m_withArgs; |
189 | - bool m_withKeyboard; |
190 | }; |
191 | |
192 | #endif |
193 | |
194 | === modified file 'src/imports/ABContactEditorPage.qml' |
195 | --- src/imports/ABContactEditorPage.qml 2015-12-16 18:35:33 +0000 |
196 | +++ src/imports/ABContactEditorPage.qml 2016-01-07 13:19:12 +0000 |
197 | @@ -26,31 +26,33 @@ |
198 | objectName: "contactEditorPage" |
199 | |
200 | property alias backIconName: backAction.iconName |
201 | - |
202 | // Property used on unit tests |
203 | readonly property alias saveActionEnabled: saveAction.enabled |
204 | |
205 | - head.backAction: Action { |
206 | - id: backAction |
207 | - |
208 | - objectName: "cancel" |
209 | - name: "cancel" |
210 | - |
211 | - text: i18n.tr("Cancel") |
212 | - iconName: "back" |
213 | - // WORKAROUND: SDK does not unregister shortcut on object destruction |
214 | - // we need to do it manually. (bug #1518420) |
215 | - enabled: root.active && root.enabled |
216 | - shortcut: enabled ? "Esc" : undefined |
217 | - onTriggered: root.cancel() |
218 | - } |
219 | - |
220 | - head.actions: [ |
221 | + leadingActions: [ |
222 | + Action { |
223 | + id: backAction |
224 | + |
225 | + objectName: "cancel" |
226 | + name: "cancel" |
227 | + text: i18n.tr("Cancel") |
228 | + iconName: "down" |
229 | + enabled: root.active && root.enabled |
230 | + shortcut: "Esc" |
231 | + onTriggered: { |
232 | + root.cancel() |
233 | + if (root.pageStack.contactListPage) |
234 | + root.pageStack.contactListPage.forceActiveFocus() |
235 | + } |
236 | + } |
237 | + ] |
238 | + |
239 | + headerActions: [ |
240 | Action { |
241 | id: saveAction |
242 | + |
243 | objectName: "save" |
244 | name: "save" |
245 | - |
246 | text: i18n.tr("Save") |
247 | iconName: "ok" |
248 | enabled: root.isContactValid && root.active && root.enabled |
249 | @@ -62,6 +64,7 @@ |
250 | onContactSaved: { |
251 | if (pageStack.contactListPage) { |
252 | pageStack.contactListPage.moveListToContact(contact) |
253 | + pageStack.contactListPage.forceActiveFocus() |
254 | } |
255 | } |
256 | } |
257 | |
258 | === modified file 'src/imports/ABContactListPage.qml' |
259 | --- src/imports/ABContactListPage.qml 2015-12-14 18:29:23 +0000 |
260 | +++ src/imports/ABContactListPage.qml 2016-01-07 13:19:12 +0000 |
261 | @@ -1,4 +1,4 @@ |
262 | -/* |
263 | +/* |
264 | * Copyright (C) 2012-2015 Canonical, Ltd. |
265 | * |
266 | * This program is free software; you can redistribute it and/or modify |
267 | @@ -26,71 +26,73 @@ |
268 | import Ubuntu.AddressBook.Base 0.1 |
269 | import Ubuntu.AddressBook.ContactShare 0.1 |
270 | |
271 | -import "." as AB |
272 | |
273 | Page { |
274 | id: mainPage |
275 | objectName: "contactListPage" |
276 | |
277 | + property var viewPage: null |
278 | property bool pickMode: false |
279 | property alias contentHubTransfer: contactExporter.activeTransfer |
280 | property bool pickMultipleContacts: false |
281 | property QtObject contactIndex: null |
282 | - property string newPhoneToAdd: "" |
283 | property alias contactManager: contactList.manager |
284 | - property alias contactViewPage: contactViewPageConnections.target |
285 | - property alias contactEditorPage: contactEditorPageConnections.target |
286 | + |
287 | property var _busyDialog: null |
288 | property bool _importingTestData: false |
289 | property bool _creatingContact: false |
290 | |
291 | - readonly property bool bottomEdgePageOpened: bottomEdge.opened && bottomEdge.fullLoaded |
292 | + readonly property string currentViewContactId: viewPage && viewPage.contact ? viewPage.contact.contactId : "" |
293 | readonly property bool isEmpty: (contactList.count === 0) |
294 | readonly property bool allowToQuit: (application.callbackApplication.length > 0) |
295 | readonly property var contactModel: contactList.listModel ? contactList.listModel : null |
296 | - readonly property bool searching: (state === "searching" || state === "newphoneSearching") |
297 | + readonly property bool searching: state === "searching" |
298 | + readonly property string headerTitle: pageHeader.title |
299 | |
300 | // this function is used to reset the contact list page to the default state if it was called |
301 | // from the uri. For example when called to add a new contact |
302 | function returnToNormalState() |
303 | { |
304 | - // these two states are the only state that need to be reset |
305 | - if (state == "newphoneSearching" || state == "newphone") { |
306 | - state = "default" |
307 | - } |
308 | application.callbackApplication = "" |
309 | } |
310 | |
311 | function createContactWithPhoneNumber(phoneNumber) |
312 | { |
313 | var newContact = ContactsJS.createEmptyContact(phoneNumber, mainPage); |
314 | - openEditPage({model: contactList.listModel, |
315 | - contact: newContact, |
316 | - initialFocusSection: "name"}, |
317 | - mainPage); |
318 | - } |
319 | - |
320 | - function openEditPage(editPageProperties, sourcePage) { |
321 | - var component = Qt.createComponent(Qt.resolvedUrl("ABContactEditorPage.qml")) |
322 | - if (component.status === Component.Ready) { |
323 | - mainPage.contactEditorPage = component.createObject(mainPage, editPageProperties) |
324 | - pageStack.addPageToNextColumn(sourcePage, mainPage.contactEditorPage) |
325 | + if (bottomEdgeLoader.status == Loader.Ready) { |
326 | + bottomEdgeLoader.editContact(newContact) |
327 | + } else { |
328 | + contactList.currentIndex = -1 |
329 | + var incubator = pageStack.addPageToNextColumn(mainPage, |
330 | + Qt.resolvedUrl("ABContactEditorPage.qml"), |
331 | + { model: mainPage.contactModel, |
332 | + contact: newContact, |
333 | + backIconName: 'back', |
334 | + enabled: false |
335 | + }) |
336 | } |
337 | } |
338 | |
339 | function openViewPage(viewPageProperties) { |
340 | var component = Qt.createComponent(Qt.resolvedUrl("ABContactViewPage.qml")) |
341 | - if (component.status === Component.Ready) { |
342 | - mainPage.contactViewPage = component.createObject(mainPage, viewPageProperties) |
343 | - pageStack.addPageToNextColumn(mainPage, mainPage.contactViewPage) |
344 | + var incubator = pageStack.addPageToNextColumn(mainPage, component, viewPageProperties) |
345 | + if (incubator && (incubator.status === Component.Loading)) { |
346 | + incubator.onStatusChanged = function(status) { |
347 | + if (status === Component.Ready) |
348 | + mainPage.viewPage = incubator.object |
349 | + } |
350 | + } else if (incubator && incubator.status ===- Component.Ready) { |
351 | + mainPage.viewPage = incubator.object |
352 | + } else { |
353 | + mainPage.viewPage = null |
354 | } |
355 | } |
356 | |
357 | function showContact(contact) |
358 | { |
359 | var currentContact = contactList.listModel.contacts[contactList.currentIndex] |
360 | - if (currentContact && contactViewPage && contactViewPage.contact && (contactViewPage.contact.contactId === currentContact.contactId)) { |
361 | - console.debug("Skip show contact") |
362 | + if (currentContact && (mainPage.currentViewContactId === currentContact.contactId)) { |
363 | + // contact view already opened with this contact |
364 | return |
365 | } |
366 | |
367 | @@ -109,13 +111,6 @@ |
368 | contactId: contactId}); |
369 | } |
370 | |
371 | - function addPhoneToContact(contactId, phoneNumber) |
372 | - { |
373 | - openViewPage({model: contactList.listModel, |
374 | - contactId: contactId, |
375 | - addPhoneToContact: phoneNumber}); |
376 | - } |
377 | - |
378 | function importContact(urls) |
379 | { |
380 | mainPage._busyDialog = PopupUtils.open(busyDialogComponent, mainPage) |
381 | @@ -157,20 +152,6 @@ |
382 | } |
383 | } |
384 | |
385 | - function addNewPhone(phoneNumber) |
386 | - { |
387 | - newPhoneToAdd = phoneNumber |
388 | - state = "newphone" |
389 | - contactList.reset() |
390 | - } |
391 | - |
392 | - function showContactEditorPage(editorPage) { |
393 | - contactList.currentIndex = -1; |
394 | - mainPage.contactEditorPage = editorPage; |
395 | - pageStack.addPageToNextColumn(mainPage, editorPage); |
396 | - editorPage.contactSaved.connect(onNewContactSaved); |
397 | - editorPage.enabled = true |
398 | - } |
399 | |
400 | function onNewContactSaved(contact) { |
401 | _creatingContact = true |
402 | @@ -190,13 +171,57 @@ |
403 | { |
404 | if ((contactList.currentIndex >= 0) && (pageStack.columns > 1)) { |
405 | var currentContact = contactList.listModel.contacts[contactList.currentIndex] |
406 | - if (contactViewPage && contactViewPage.contact && (contactViewPage.contact.contactId === currentContact.contactId)) |
407 | + if (!currentContact) { |
408 | + var component = Qt.createComponent(Qt.resolvedUrl("ABMultiColumnEmptyState.qml")) |
409 | + var searching = contactList.filterTerm !== "" |
410 | + pageStack.addPageToNextColumn(mainPage, component, |
411 | + { headerTitle: searching ? i18n.tr("No contact found") : i18n.tr("No contacts") }) |
412 | + return |
413 | + } |
414 | + if (currentContact && (mainPage.currentViewContactId === currentContact.contactId)) |
415 | return |
416 | |
417 | contactList.view._fetchContact(contactList.currentIndex, currentContact) |
418 | } |
419 | } |
420 | |
421 | + header: PageHeader { |
422 | + id: pageHeader |
423 | + |
424 | + property alias leadingActions: leadingBar.actions |
425 | + property alias trailingActions: trailingBar.actions |
426 | + property alias sectionsModel: sections.model |
427 | + |
428 | + title: i18n.tr("Contacts") |
429 | + //flickable: contactList.view |
430 | + trailingActionBar { |
431 | + id: trailingBar |
432 | + } |
433 | + leadingActionBar { |
434 | + id: leadingBar |
435 | + } |
436 | + extension: Sections { |
437 | + id: sections |
438 | + anchors { |
439 | + left: parent.left |
440 | + leftMargin: units.gu(2) |
441 | + bottom: parent.bottom |
442 | + } |
443 | + onSelectedIndexChanged: { |
444 | + switch (selectedIndex) { |
445 | + case 0: |
446 | + contactList.showAllContacts() |
447 | + break; |
448 | + case 1: |
449 | + contactList.showFavoritesContacts() |
450 | + break; |
451 | + default: |
452 | + break; |
453 | + } |
454 | + } |
455 | + } |
456 | + } |
457 | + |
458 | // This timer is to avoid fetch unecessary contact if the user select the contacts too fast |
459 | // while navigating on contact list with keyboard |
460 | Timer { |
461 | @@ -215,23 +240,23 @@ |
462 | objectName: "contactListView" |
463 | |
464 | focus: true |
465 | - showImportOptions: !mainPage.pickMode && |
466 | - mainPage.newPhoneToAdd === "" && |
467 | - (!mainPage.contactEditorPage || !mainPage.contactEditorPage.active) |
468 | + showImportOptions: !mainPage.pickMode && |
469 | + pageStack.bottomEdge && |
470 | + (pageStack.bottomEdge.status === BottomEdge.Hidden) |
471 | anchors { |
472 | top: parent.top |
473 | + topMargin: pageHeader.height |
474 | left: parent.left |
475 | bottom: keyboard.top |
476 | right: parent.right |
477 | } |
478 | - currentIndex: 0 |
479 | + currentIndex: -1 |
480 | filterTerm: searchField.text |
481 | multiSelectionEnabled: true |
482 | multipleSelection: (mainPage.pickMode && mainPage.pickMultipleContacts) || !mainPage.pickMode |
483 | - highlightSelected: application.usingKeyboard && !mainPage._creatingContact |
484 | + showNewContact: (pageStack.columns > 1) && pageStack.bottomEdge && (pageStack.bottomEdge.status === BottomEdge.Committed) |
485 | + highlightSelected: pageStack.hasKeyboard && !mainPage._creatingContact |
486 | onAddContactClicked: mainPage.createContactWithPhoneNumber(label) |
487 | - onAddNewContactClicked: mainPage.createContactWithPhoneNumber(mainPage.newPhoneToAdd) |
488 | - |
489 | onContactClicked: mainPage.showContact(contact) |
490 | onIsInSelectionModeChanged: mainPage.state = isInSelectionMode ? "selection" : "default" |
491 | onSelectionCanceled: { |
492 | @@ -252,14 +277,17 @@ |
493 | contactList.currentIndex = 0 |
494 | } |
495 | } |
496 | + |
497 | onCountChanged: { |
498 | if (mainPage.active && |
499 | (pageStack.columns > 1) && |
500 | - (contactList.currentIndex === -1)) { |
501 | + (contactList.currentIndex === -1) && |
502 | + (pageStack.bottomEdge.status === BottomEdge.Hidden)) { |
503 | contactList.currentIndex = 0 |
504 | } |
505 | mainPage.delayFetchContact() |
506 | } |
507 | + |
508 | onCurrentIndexChanged: { |
509 | if (!mainPage.contactIndex) |
510 | mainPage.delayFetchContact() |
511 | @@ -267,7 +295,7 @@ |
512 | |
513 | Keys.onReturnPressed: { |
514 | var currentContact = contactList.listModel.contacts[contactList.currentIndex] |
515 | - if (contactViewPage && contactViewPage.contact && (contactViewPage.contact.contactId === currentContact.contactId)) |
516 | + if (mainPage.currentViewContactId === currentContact.contactId) |
517 | return |
518 | |
519 | contactList.view._fetchContact(contactList.currentIndex, currentContact) |
520 | @@ -277,7 +305,7 @@ |
521 | //because of that we need this |
522 | Keys.onRightPressed: { |
523 | // only move focus away when in edit mode |
524 | - if (mainPage.contactEditorPage) { |
525 | + if (pageStack.bottomEdge.status === BottomEdge.Committed) { |
526 | var next = pageStack._nextItemInFocusChain(view, true) |
527 | if (next === searchField) { |
528 | pageStack._nextItemInFocusChain(next, true) |
529 | @@ -292,8 +320,6 @@ |
530 | } |
531 | } |
532 | |
533 | - |
534 | - |
535 | TextField { |
536 | id: searchField |
537 | |
538 | @@ -302,58 +328,57 @@ |
539 | readonly property bool _allowFocus: true |
540 | |
541 | anchors { |
542 | + top: parent ? parent.top : undefined |
543 | left: parent ? parent.left : undefined |
544 | right: parent ? parent.right : undefined |
545 | + margins: units.gu(1) |
546 | rightMargin: units.gu(2) |
547 | } |
548 | |
549 | visible: false |
550 | inputMethodHints: Qt.ImhNoPredictiveText |
551 | placeholderText: i18n.tr("Search...") |
552 | + onVisibleChanged: { |
553 | + if (visible) { |
554 | + if (activeFocus) { |
555 | + Qt.inputMethod.show() |
556 | + } else { |
557 | + searchField.forceActiveFocus() |
558 | + } |
559 | + } |
560 | + } |
561 | + |
562 | Keys.onTabPressed: contactList.forceActiveFocus() |
563 | Keys.onDownPressed: contactList.forceActiveFocus() |
564 | } |
565 | |
566 | - Connections { |
567 | - target: mainPage.head.sections |
568 | - onSelectedIndexChanged: { |
569 | - switch (mainPage.head.sections.selectedIndex) { |
570 | - case 0: |
571 | - contactList.showAllContacts() |
572 | - break; |
573 | - case 1: |
574 | - contactList.showFavoritesContacts() |
575 | - break; |
576 | - default: |
577 | - break; |
578 | - } |
579 | - } |
580 | - } |
581 | - |
582 | state: "default" |
583 | states: [ |
584 | - PageHeadState { |
585 | + State { |
586 | id: defaultState |
587 | - |
588 | name: "default" |
589 | - backAction: Action { |
590 | - visible: mainPage.allowToQuit |
591 | - iconName: "back" |
592 | - text: i18n.tr("Quit") |
593 | - onTriggered: { |
594 | - application.goBackToSourceApp() |
595 | - mainPage.returnToNormalState() |
596 | + |
597 | + property list<QtObject> leadingActions: [ |
598 | + Action { |
599 | + visible: mainPage.allowToQuit |
600 | + iconName: "back" |
601 | + text: i18n.tr("Quit") |
602 | + onTriggered: { |
603 | + application.goBackToSourceApp() |
604 | + mainPage.returnToNormalState() |
605 | + } |
606 | } |
607 | - } |
608 | - actions: [ |
609 | + ] |
610 | + |
611 | + property list<QtObject> trailingActions: [ |
612 | Action { |
613 | text: i18n.tr("Search") |
614 | iconName: "search" |
615 | visible: !mainPage.isEmpty |
616 | - enabled: mainPage.state === "default" |
617 | + enabled: visible && (mainPage.state === "default") |
618 | shortcut: "Ctrl+F" |
619 | onTriggered: { |
620 | - mainPage.state = (mainPage.state === "newphone" ? "newphoneSearching" : "searching") |
621 | + mainPage.state = "searching" |
622 | contactList.showAllContacts() |
623 | searchField.forceActiveFocus() |
624 | } |
625 | @@ -391,73 +416,85 @@ |
626 | } |
627 | } |
628 | ] |
629 | + |
630 | PropertyChanges { |
631 | - target: mainPage.head |
632 | - backAction: defaultState.backAction |
633 | - actions: defaultState.actions |
634 | + target: pageHeader |
635 | + |
636 | // TRANSLATORS: this refers to all contacts |
637 | - sections.model: [i18n.tr("All"), i18n.tr("Favorites")] |
638 | + sectionsModel: [i18n.tr("All"), i18n.tr("Favorites")] |
639 | + leadingActions: defaultState.leadingActions |
640 | + trailingActions: defaultState.trailingActions |
641 | } |
642 | PropertyChanges { |
643 | target: searchField |
644 | text: "" |
645 | } |
646 | PropertyChanges { |
647 | - target: bottomEdge |
648 | + target: bottomEdgeLoader |
649 | enabled: true |
650 | } |
651 | }, |
652 | - PageHeadState { |
653 | + State { |
654 | id: searchingState |
655 | - |
656 | name: "searching" |
657 | - backAction: Action { |
658 | - iconName: "back" |
659 | - text: i18n.tr("Cancel") |
660 | - enabled: mainPage.state === "searching" && !mainPage.contactEditorPage && mainPage.active |
661 | - shortcut: "Esc" |
662 | - onTriggered: { |
663 | - mainPage.head.sections.selectedIndex = 0 |
664 | - mainPage.state = (mainPage.state === "newphoneSearching" ? "newphone" : "default") |
665 | - contactList.forceActiveFocus() |
666 | + |
667 | + property list<QtObject> leadingActions: [ |
668 | + Action { |
669 | + iconName: "back" |
670 | + text: i18n.tr("Cancel") |
671 | + enabled: (mainPage.state === "searching") && |
672 | + mainPage.active && |
673 | + (!pageStack.bottomEdge || |
674 | + (pageStack.bottomEdge && (pageStack.bottomEdge.status === BottomEdge.Hidden))) && |
675 | + ((pageStack.columns === 1) || |
676 | + (mainPage.viewPage && mainPage.viewPage.active)) |
677 | + shortcut:"Esc" |
678 | + onTriggered: { |
679 | + mainPage.head.sections.selectedIndex = 0 |
680 | + mainPage.state = "default" |
681 | + contactList.forceActiveFocus() |
682 | + } |
683 | } |
684 | - } |
685 | - |
686 | - PropertyChanges { |
687 | - target: bottomEdge |
688 | - enabled: false |
689 | - } |
690 | - |
691 | - PropertyChanges { |
692 | - target: mainPage.head |
693 | - backAction: searchingState.backAction |
694 | + ] |
695 | + |
696 | + PropertyChanges { |
697 | + target: pageHeader |
698 | + |
699 | contents: searchField |
700 | + leadingActions: searchingState.leadingActions |
701 | + |
702 | } |
703 | |
704 | PropertyChanges { |
705 | - target: searchField |
706 | - text: "" |
707 | + target: bottomEdgeLoader |
708 | + enabled: false |
709 | } |
710 | |
711 | PropertyChanges { |
712 | target: searchField |
713 | visible: true |
714 | focus: true |
715 | + text: "" |
716 | } |
717 | }, |
718 | - PageHeadState { |
719 | + State { |
720 | id: selectionState |
721 | - |
722 | name: "selection" |
723 | - backAction: Action { |
724 | - text: i18n.tr("Cancel selection") |
725 | - iconName: "back" |
726 | - enabled: mainPage.state === "selection" |
727 | - shortcut: "Esc" |
728 | - onTriggered: contactList.cancelSelection() |
729 | - } |
730 | - actions: [ |
731 | + |
732 | + property list<QtObject> leadingActions: [ |
733 | Action { |
734 | + objectName: "cancel" |
735 | + name: "cancel" |
736 | + text: i18n.tr("Cancel selection") |
737 | + iconName: "back" |
738 | + enabled: mainPage.state === "selection" |
739 | + onTriggered: contactList.cancelSelection() |
740 | + shortcut: "Esc" |
741 | + } |
742 | + ] |
743 | + |
744 | + property list<QtObject> trailingActions: [ |
745 | + Action { |
746 | text: (contactList.selectedItems.count === contactList.count) ? i18n.tr("Unselect All") : i18n.tr("Select All") |
747 | iconName: "select" |
748 | onTriggered: { |
749 | @@ -506,76 +543,48 @@ |
750 | } |
751 | } |
752 | ] |
753 | - PropertyChanges { |
754 | - target: mainPage.head |
755 | - backAction: selectionState.backAction |
756 | - actions: selectionState.actions |
757 | - } |
758 | - PropertyChanges { |
759 | - target: bottomEdge |
760 | - enabled: false |
761 | - } |
762 | - }, |
763 | - PageHeadState { |
764 | - name: "newphone" |
765 | - extend: "default" |
766 | - head: mainPage.head |
767 | - PropertyChanges { |
768 | - target: contactList |
769 | - showAddNewButton: true |
770 | - } |
771 | - PropertyChanges { |
772 | - target: mainPage |
773 | - title: i18n.tr("Add contact") |
774 | - } |
775 | - PropertyChanges { |
776 | - target: bottomEdge |
777 | - enabled: false |
778 | - } |
779 | - PropertyChanges { |
780 | - target: contactList |
781 | - detailToPick: -1 |
782 | - } |
783 | - }, |
784 | - PageHeadState { |
785 | - name: "newphoneSearching" |
786 | - extend: "searching" |
787 | - head: mainPage.head |
788 | - PropertyChanges { |
789 | - target: contactList |
790 | - detailToPick: -1 |
791 | - showAddNewButton: true |
792 | - } |
793 | - PropertyChanges { |
794 | - target: bottomEdge |
795 | - enabled: false |
796 | - } |
797 | - }, |
798 | - PageHeadState { |
799 | + |
800 | + PropertyChanges { |
801 | + target: pageHeader |
802 | + |
803 | + leadingActions: selectionState.leadingActions |
804 | + trailingActions: selectionState.trailingActions |
805 | + } |
806 | + |
807 | + PropertyChanges { |
808 | + target: bottomEdgeLoader |
809 | + enabled: false |
810 | + } |
811 | + }, |
812 | + State { |
813 | id: vcardImportedState |
814 | - |
815 | name: "vcardImported" |
816 | - backAction: Action { |
817 | - iconName: "back" |
818 | - text: i18n.tr("Back") |
819 | - onTriggered: { |
820 | - contactList.forceActiveFocus() |
821 | - mainPage.state = "default" |
822 | - importedIdsFilter.ids = [] |
823 | + |
824 | + property list<QtObject> leadingActions: [ |
825 | + Action { |
826 | + objectName: "cancel" |
827 | + name: "cancel" |
828 | + iconName: "back" |
829 | + text: i18n.tr("Back") |
830 | + onTriggered: { |
831 | + contactList.forceActiveFocus() |
832 | + mainPage.state = "default" |
833 | + importedIdsFilter.ids = [] |
834 | + } |
835 | } |
836 | - } |
837 | - PropertyChanges { |
838 | - target: mainPage.head |
839 | - backAction: vcardImportedState.backAction |
840 | - } |
841 | - PropertyChanges { |
842 | - target: bottomEdge |
843 | - enabled: false |
844 | - } |
845 | - PropertyChanges { |
846 | - target: mainPage |
847 | + ] |
848 | + |
849 | + PropertyChanges { |
850 | + target: pageHeader |
851 | + |
852 | + leadingActions: vcardImportedState.leadingActions |
853 | title: i18n.tr("Imported contacts") |
854 | } |
855 | + |
856 | + PropertyChanges { |
857 | + target: bottomEdgeLoader |
858 | + enabled: false |
859 | + } |
860 | } |
861 | ] |
862 | |
863 | @@ -614,54 +623,30 @@ |
864 | |
865 | KeyboardRectangle { |
866 | id: keyboard |
867 | + active: mainPage.active && |
868 | + (pageStack.bottomEdge && (pageStack.bottomEdge.status === BottomEdge.Hidden)) |
869 | } |
870 | |
871 | - Column { |
872 | + ABEmptyState { |
873 | id: emptyStateScreen |
874 | |
875 | - anchors.centerIn: parent |
876 | + anchors { |
877 | + verticalCenter: parent.verticalCenter |
878 | + left: parent.left |
879 | + right: parent.right |
880 | + leftMargin: units.gu(6) |
881 | + rightMargin: units.gu(6) |
882 | + } |
883 | + |
884 | height: childrenRect.height |
885 | - width: childrenRect.width |
886 | - spacing: units.gu(2) |
887 | - visible: (!contactList.busy && |
888 | + visible: ((pageStack.columns === 1) && |
889 | + !contactList.busy && |
890 | !contactList.favouritesIsSelected && |
891 | mainPage.isEmpty && |
892 | - (mainPage.newPhoneToAdd === "") && |
893 | - !(contactList.filterTerm && contactList.filterTerm !== "")) && |
894 | - bottomEdge.visible |
895 | - |
896 | - Behavior on visible { |
897 | - SequentialAnimation { |
898 | - PauseAnimation { |
899 | - duration: !emptyStateScreen.visible ? 500 : 0 |
900 | - } |
901 | - PropertyAction { |
902 | - target: emptyStateScreen |
903 | - property: "visible" |
904 | - } |
905 | - } |
906 | - } |
907 | - |
908 | - Icon { |
909 | - id: emptyStateIcon |
910 | - anchors.horizontalCenter: emptyStateLabel.horizontalCenter |
911 | - height: units.gu(5) |
912 | - width: units.gu(5) |
913 | - opacity: 0.3 |
914 | - name: "contact" |
915 | - } |
916 | - Label { |
917 | - id: emptyStateLabel |
918 | - width: mainPage.width - units.gu(12) |
919 | - height: paintedHeight |
920 | - text: mainPage.pickMode ? |
921 | - i18n.tr("You have no contacts.") : |
922 | - i18n.tr("Create a new contact by swiping up from the bottom of the screen.") |
923 | - color: "#5d5d5d" |
924 | - fontSize: "x-large" |
925 | - wrapMode: Text.WordWrap |
926 | - horizontalAlignment: Text.AlignHCenter |
927 | - } |
928 | + !(contactList.filterTerm && contactList.filterTerm !== "")) |
929 | + text: mainPage.pickMode ? |
930 | + i18n.tr("You have no contacts.") : |
931 | + i18n.tr("Create a new contact by swiping up from the bottom of the screen.") |
932 | } |
933 | |
934 | ContactExporter { |
935 | @@ -753,103 +738,26 @@ |
936 | } |
937 | } |
938 | |
939 | - Component { |
940 | - id: editorPageBottomEdge |
941 | - ABContactEditorPage { |
942 | - backIconName: "down" |
943 | - implicitWidth: mainPage.width |
944 | - implicitHeight: mainPage.height |
945 | - model: contactList.listModel |
946 | - contact: ContactsJS.createEmptyContact("", mainPage) |
947 | - initialFocusSection: "name" |
948 | - enabled: false |
949 | - } |
950 | - } |
951 | - |
952 | - Component { |
953 | - id: emptyContact |
954 | - ContactsUI.ContactDelegate { |
955 | - property Contact contact: Contact { |
956 | - Name { |
957 | - firstName: i18n.tr("New contact") |
958 | - } |
959 | - Avatar { |
960 | - imageUrl: "image://theme/contact" |
961 | - } |
962 | - } |
963 | - width: mainPage.width |
964 | - } |
965 | - } |
966 | - |
967 | - AB.BottomEdge { |
968 | - id: bottomEdge |
969 | - objectName: "bottomEdge" |
970 | - |
971 | - property var incubator |
972 | - |
973 | - // FIXME: this is a workaround for the lack of fully asynchronous loading |
974 | - // of Pages in AdaptativePageLayout |
975 | - function createObjectAsynchronously(url, properties, callback) { |
976 | - var component = Qt.createComponent(url, Component.Asynchronous); |
977 | - if (component.status == Component.Ready) { |
978 | - incubateObject(component, properties, callback); |
979 | - } else { |
980 | - component.onStatusChanged.connect(function(status) { |
981 | - if (status == Component.Ready) { |
982 | - incubateObject(component, properties, callback); |
983 | - } |
984 | - }); |
985 | - } |
986 | - } |
987 | - |
988 | - function incubateObject(component, properties, callback) { |
989 | - if (component.status == Component.Ready) { |
990 | - incubator = component.incubateObject(null, |
991 | - properties, |
992 | - Qt.Asynchronous); |
993 | - incubator.onStatusChanged = function(status) { |
994 | - if (status == Component.Ready) { |
995 | - callback(incubator.object); |
996 | - incubator = null; |
997 | - } |
998 | - } |
999 | - } |
1000 | - } |
1001 | - |
1002 | - function loadEditorPage() { |
1003 | - var newContact = ContactsJS.createEmptyContact("", mainPage); |
1004 | - createObjectAsynchronously(Qt.resolvedUrl("ABContactEditorPage.qml"), |
1005 | - {model: contactList.listModel, |
1006 | - enabled: false, |
1007 | - contact: newContact, |
1008 | - initialFocusSection: "name"}, |
1009 | - showContactEditorPage); |
1010 | - } |
1011 | - |
1012 | - anchors.fill: parent |
1013 | - contentComponent: pageStack.columns === 1 ? editorPageBottomEdge : emptyContact |
1014 | - flickable: contactList |
1015 | - iconName: "contact-new" |
1016 | - backGroundEffectEnabled: pageStack.columns === 1 |
1017 | - |
1018 | - onBottomEdgeLoaded: contactList.forceActiveFocus() |
1019 | - onOpenBegin: { |
1020 | - contactList.prepareNewContact = true; |
1021 | - contactList.positionViewAtBeginning(); |
1022 | - if (pageStack.columns > 1) { |
1023 | - loadEditorPage(); |
1024 | - } |
1025 | - } |
1026 | - onOpenEnd: { |
1027 | - contactList.showNewContact = true; |
1028 | - if (pageStack.columns <= 1) { |
1029 | - showContactEditorPage(bottomEdge.content); |
1030 | - } |
1031 | - } |
1032 | - |
1033 | - onClicked: { |
1034 | - bottomEdge.open(); |
1035 | - } |
1036 | + Loader { |
1037 | + id: bottomEdgeLoader |
1038 | + |
1039 | + enabled: false |
1040 | + active: (pageStack.columns === 1) && bottomEdgeLoader.enabled |
1041 | + asynchronous: true |
1042 | + sourceComponent: ABNewContactBottomEdge { |
1043 | + parent: mainPage |
1044 | + modelToEdit: mainPage.contactModel |
1045 | + hint.flickable: contactList.view |
1046 | + pageStack: mainPage.pageStack |
1047 | + enabled: mainPage.active |
1048 | + } |
1049 | + } |
1050 | + |
1051 | + Binding { |
1052 | + target: pageStack |
1053 | + property: 'bottomEdge' |
1054 | + value: bottomEdgeLoader.item |
1055 | + when: bottomEdgeLoader.status == Loader.Ready |
1056 | } |
1057 | |
1058 | Connections { |
1059 | @@ -861,6 +769,7 @@ |
1060 | mainPage.contactIndex = null |
1061 | // at this point the operation has finished already |
1062 | mainPage._creatingContact = false |
1063 | + fetchNewContactTimer.restart() |
1064 | } |
1065 | } |
1066 | onImportCompleted: { |
1067 | @@ -890,34 +799,20 @@ |
1068 | } |
1069 | |
1070 | Connections { |
1071 | - id: contactViewPageConnections |
1072 | - |
1073 | - ignoreUnknownSignals: true |
1074 | - onEditContact: openEditPage(editPageProperties, mainPage.contactViewPage); |
1075 | - onActiveChanged: { |
1076 | - if (mainPage.contactViewPage && |
1077 | - !mainPage.contactViewPage.active && |
1078 | - (mainPage.contactEditorPage == null)) { // not editing |
1079 | - mainPage.contactViewPage = null |
1080 | + target: pageStack.bottomEdge |
1081 | + onCommitCompleted: { |
1082 | + if (mainPage.state !== "default") { |
1083 | + mainPage.head.sections.selectedIndex = 0 |
1084 | + mainPage.state = "default" |
1085 | } |
1086 | } |
1087 | - } |
1088 | - |
1089 | - Connections { |
1090 | - id: contactEditorPageConnections |
1091 | - |
1092 | - ignoreUnknownSignals: true |
1093 | - onActiveChanged: { |
1094 | - if (mainPage.contactEditorPage && !mainPage.contactEditorPage.active) { |
1095 | - contactList.prepareNewContact = false; |
1096 | - contactList.showNewContact = false; |
1097 | - bottomEdge.close(); |
1098 | - mainPage.contactEditorPage = null |
1099 | - contactList.forceActiveFocus() |
1100 | - bottomEdge.enabled = true |
1101 | - } else if (mainPage.contactEditorPage && !mainPage.contactEditorPage.active) { |
1102 | - bottomEdge.enabled = false |
1103 | + onCollapseCompleted: { |
1104 | + if (!mainPage._creatingContact) { |
1105 | + if (contactList.currentIndex === -1) |
1106 | + contactList.currentIndex = 0 |
1107 | + mainPage.delayFetchContact() |
1108 | } |
1109 | + contactList.forceActiveFocus() |
1110 | } |
1111 | } |
1112 | } |
1113 | |
1114 | === modified file 'src/imports/ABContactViewPage.qml' |
1115 | --- src/imports/ABContactViewPage.qml 2015-12-14 18:29:23 +0000 |
1116 | +++ src/imports/ABContactViewPage.qml 2016-01-07 13:19:12 +0000 |
1117 | @@ -1,4 +1,4 @@ |
1118 | -/* |
1119 | +/* |
1120 | * Copyright (C) 2012-2015 Canonical, Ltd. |
1121 | * |
1122 | * This program is free software; you can redistribute it and/or modify |
1123 | @@ -27,10 +27,35 @@ |
1124 | id: root |
1125 | objectName: "contactViewPage" |
1126 | |
1127 | - property string addPhoneToContact: "" |
1128 | - signal editContact(var editPageProperties) |
1129 | - |
1130 | - // Override Action buttom to add shortcut to it |
1131 | + property bool editing: false |
1132 | + // used by autopilot test |
1133 | + readonly property string headerTitle: header.title |
1134 | + |
1135 | + function editContact(contact) |
1136 | + { |
1137 | + if (editing) |
1138 | + return |
1139 | + editing = true |
1140 | + var component = Qt.createComponent(Qt.resolvedUrl("ABContactEditorPage.qml")) |
1141 | + var incubator = pageStack.addPageToCurrentColumn(root, |
1142 | + component, |
1143 | + { model: root.model, |
1144 | + contact: contact, |
1145 | + backIconName: 'back'}) |
1146 | + if (incubator && (incubator.status === Component.Loading)) { |
1147 | + incubator.onStatusChanged = function(status) { |
1148 | + if (status === Component.Ready) { |
1149 | + incubator.object.Component.destruction.connect(function() { |
1150 | + root.editing = false; |
1151 | + }); |
1152 | + } |
1153 | + } |
1154 | + } else { |
1155 | + editing = false |
1156 | + } |
1157 | + } |
1158 | + |
1159 | + // Shortcut in case of single column |
1160 | Action { |
1161 | id: backAction |
1162 | |
1163 | @@ -40,7 +65,8 @@ |
1164 | onTriggered: pageStack.removePages(root) |
1165 | } |
1166 | |
1167 | - head.actions: [ |
1168 | + |
1169 | + headerActions: [ |
1170 | Action { |
1171 | objectName: "share" |
1172 | name: "share" |
1173 | @@ -60,12 +86,9 @@ |
1174 | |
1175 | text: i18n.tr("Edit") |
1176 | iconName: "edit" |
1177 | - enabled: root.active |
1178 | + enabled: root.active && !editing |
1179 | shortcut: "Ctrl+e" |
1180 | - onTriggered: { |
1181 | - editContact({model: root.model, |
1182 | - contact: root.contact}); |
1183 | - } |
1184 | + onTriggered: root.editContact(root.contact) |
1185 | } |
1186 | ] |
1187 | |
1188 | @@ -80,23 +103,6 @@ |
1189 | height: implicitHeight |
1190 | } |
1191 | |
1192 | - // This will load the contact information when the app was launched with |
1193 | - // the URI: addressbook:///contact?id=<id> |
1194 | - onContactFetched: { |
1195 | - if (root.addPhoneToContact != "") { |
1196 | - var detailSourceTemplate = "import QtContacts 5.0; PhoneNumber{ number: \"" + root.addPhoneToContact.trim() + "\" }" |
1197 | - var newDetail = Qt.createQmlObject(detailSourceTemplate, contact) |
1198 | - if (newDetail) { |
1199 | - contact.addDetail(newDetail) |
1200 | - editContact({ model: root.model, |
1201 | - contact: contact, |
1202 | - initialFocusSection: "phones", |
1203 | - newDetails: [newDetail] }) |
1204 | - root.addPhoneToContact = "" |
1205 | - } |
1206 | - } |
1207 | - } |
1208 | - |
1209 | onActionTrigerred: { |
1210 | // "default" action is used inside of the apps (dialer, messaging) to trigger |
1211 | // actions based on context. |
1212 | @@ -112,4 +118,27 @@ |
1213 | id: contactShareComponent |
1214 | ContactSharePage {} |
1215 | } |
1216 | + |
1217 | + Loader { |
1218 | + id: bottomEdgeLoader |
1219 | + |
1220 | + active: (pageStack.columns > 1) |
1221 | + asynchronous: true |
1222 | + sourceComponent: ABNewContactBottomEdge { |
1223 | + id: bottomEdge |
1224 | + |
1225 | + parent: root |
1226 | + height: root.height |
1227 | + modelToEdit: root.model |
1228 | + hint.flickable: root.flickable |
1229 | + pageStack: root.pageStack |
1230 | + } |
1231 | + } |
1232 | + |
1233 | + Binding { |
1234 | + target: pageStack |
1235 | + property: 'bottomEdge' |
1236 | + value: bottomEdgeLoader.item |
1237 | + when: bottomEdgeLoader.status === Loader.Ready |
1238 | + } |
1239 | } |
1240 | |
1241 | === added file 'src/imports/ABEmptyState.qml' |
1242 | --- src/imports/ABEmptyState.qml 1970-01-01 00:00:00 +0000 |
1243 | +++ src/imports/ABEmptyState.qml 2016-01-07 13:19:12 +0000 |
1244 | @@ -0,0 +1,61 @@ |
1245 | +/* |
1246 | + * Copyright (C) 2012-2016 Canonical, Ltd. |
1247 | + * |
1248 | + * This program is free software; you can redistribute it and/or modify |
1249 | + * it under the terms of the GNU General Public License as published by |
1250 | + * the Free Software Foundation; version 3. |
1251 | + * |
1252 | + * This program is distributed in the hope that it will be useful, |
1253 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1254 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1255 | + * GNU General Public License for more details. |
1256 | + * |
1257 | + * You should have received a copy of the GNU General Public License |
1258 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1259 | + */ |
1260 | + |
1261 | +import QtQuick 2.4 |
1262 | +import Ubuntu.Components 1.3 |
1263 | + |
1264 | +Column { |
1265 | + id: root |
1266 | + |
1267 | + property alias text: emptyStateLabel.text |
1268 | + |
1269 | + spacing: units.gu(2) |
1270 | + //implicitHeight: childrenRect.height |
1271 | + |
1272 | + Behavior on visible { |
1273 | + SequentialAnimation { |
1274 | + PauseAnimation { |
1275 | + duration: !root.visible ? 500 : 0 |
1276 | + } |
1277 | + PropertyAction { |
1278 | + target: root |
1279 | + property: "visible" |
1280 | + } |
1281 | + } |
1282 | + } |
1283 | + |
1284 | + Icon { |
1285 | + id: emptyStateIcon |
1286 | + anchors.horizontalCenter: emptyStateLabel.horizontalCenter |
1287 | + height: units.gu(5) |
1288 | + width: units.gu(5) |
1289 | + opacity: 0.3 |
1290 | + name: "contact" |
1291 | + } |
1292 | + Label { |
1293 | + id: emptyStateLabel |
1294 | + anchors { |
1295 | + left: parent.left |
1296 | + right: parent.right |
1297 | + } |
1298 | + height: paintedHeight |
1299 | + text: i18n.tr("Create a new contact by swiping up from the bottom of the screen.") |
1300 | + color: "#5d5d5d" |
1301 | + fontSize: "x-large" |
1302 | + wrapMode: Text.WordWrap |
1303 | + horizontalAlignment: Text.AlignHCenter |
1304 | + } |
1305 | +} |
1306 | |
1307 | === added file 'src/imports/ABMultiColumnEmptyState.qml' |
1308 | --- src/imports/ABMultiColumnEmptyState.qml 1970-01-01 00:00:00 +0000 |
1309 | +++ src/imports/ABMultiColumnEmptyState.qml 2016-01-07 13:19:12 +0000 |
1310 | @@ -0,0 +1,75 @@ |
1311 | +/* |
1312 | + * Copyright (C) 2012-2016 Canonical, Ltd. |
1313 | + * |
1314 | + * This program is free software; you can redistribute it and/or modify |
1315 | + * it under the terms of the GNU General Public License as published by |
1316 | + * the Free Software Foundation; version 3. |
1317 | + * |
1318 | + * This program is distributed in the hope that it will be useful, |
1319 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1320 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1321 | + * GNU General Public License for more details. |
1322 | + * |
1323 | + * You should have received a copy of the GNU General Public License |
1324 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1325 | + */ |
1326 | + |
1327 | +import QtQuick 2.4 |
1328 | +import Ubuntu.Components 1.3 |
1329 | + |
1330 | + |
1331 | +Page { |
1332 | + id: root |
1333 | + |
1334 | + property string headerTitle: i18n.tr("No contacts") |
1335 | + |
1336 | + header: PageHeader { |
1337 | + title: root.headerTitle |
1338 | + } |
1339 | + |
1340 | + ABEmptyState { |
1341 | + id: emptyStateScreen |
1342 | + |
1343 | + anchors { |
1344 | + verticalCenter: parent.verticalCenter |
1345 | + left: parent.left |
1346 | + right: parent.right |
1347 | + leftMargin: units.gu(6) |
1348 | + rightMargin: units.gu(6) |
1349 | + } |
1350 | + height: childrenRect.height |
1351 | + text: i18n.tr("Create a new contact by swiping up from the bottom of the screen.") |
1352 | + } |
1353 | + |
1354 | + Loader { |
1355 | + id: bottomEdgeLoader |
1356 | + |
1357 | + active: (pageStack.columns > 1) |
1358 | + asynchronous: true |
1359 | + sourceComponent: ABNewContactBottomEdge { |
1360 | + id: bottomEdge |
1361 | + |
1362 | + parent: root |
1363 | + height: root.height |
1364 | + modelToEdit: root.pageStack.contactListPage.contactModel |
1365 | + hint.flickable: root.flickable |
1366 | + pageStack: root.pageStack |
1367 | + } |
1368 | + } |
1369 | + |
1370 | + Binding { |
1371 | + target: pageStack |
1372 | + property: 'bottomEdge' |
1373 | + value: bottomEdgeLoader.item |
1374 | + when: bottomEdgeLoader.status === Loader.Ready |
1375 | + } |
1376 | + |
1377 | + Connections { |
1378 | + target: pageStack |
1379 | + onColumnsChanged: { |
1380 | + if (pageStack.columns === 1) { |
1381 | + pageStack.removePages(root) |
1382 | + } |
1383 | + } |
1384 | + } |
1385 | +} |
1386 | |
1387 | === added file 'src/imports/ABNewContactBottomEdge.qml' |
1388 | --- src/imports/ABNewContactBottomEdge.qml 1970-01-01 00:00:00 +0000 |
1389 | +++ src/imports/ABNewContactBottomEdge.qml 2016-01-07 13:19:12 +0000 |
1390 | @@ -0,0 +1,89 @@ |
1391 | +/* |
1392 | + * Copyright (C) 2012-2015 Canonical, Ltd. |
1393 | + * |
1394 | + * This program is free software; you can redistribute it and/or modify |
1395 | + * it under the terms of the GNU General Public License as published by |
1396 | + * the Free Software Foundation; version 3. |
1397 | + * |
1398 | + * This program is distributed in the hope that it will be useful, |
1399 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1400 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1401 | + * GNU General Public License for more details. |
1402 | + * |
1403 | + * You should have received a copy of the GNU General Public License |
1404 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1405 | + */ |
1406 | + |
1407 | +import QtQuick 2.4 |
1408 | +import Ubuntu.Components 1.3 |
1409 | +import Ubuntu.Contacts 0.1 as ContactsUI |
1410 | + |
1411 | +BottomEdge { |
1412 | + id: bottomEdge |
1413 | + objectName: "bottomEdge" |
1414 | + |
1415 | + property var modelToEdit: null |
1416 | + property var pageStack: null |
1417 | + property var _contactToEdit: null |
1418 | + // WORKAROUND: BottomEdge component loads the page async while draging it |
1419 | + // this cause a very bad visual. |
1420 | + // To avoid that we create it as soon as the component is ready and keep |
1421 | + // it invisible until the user start to drag it. |
1422 | + property var _realPage: null |
1423 | + |
1424 | + function editContact(contact) |
1425 | + { |
1426 | + _contactToEdit = contact |
1427 | + commit() |
1428 | + } |
1429 | + |
1430 | + hint { |
1431 | + action: Action { |
1432 | + iconName: "contact-new" |
1433 | + shortcut: "ctrl+n" |
1434 | + enabled: bottomEdge.enabled |
1435 | + |
1436 | + onTriggered: bottomEdge.commit() |
1437 | + } |
1438 | + } |
1439 | + |
1440 | + contentComponent: Item { |
1441 | + id: pageContent |
1442 | + |
1443 | + implicitWidth: bottomEdge.width |
1444 | + implicitHeight: bottomEdge.height |
1445 | + children: bottomEdge._realPage |
1446 | + } |
1447 | + |
1448 | + |
1449 | + onCommitCompleted: { |
1450 | + if (bottomEdge._contactToEdit) |
1451 | + editorPage.contact = bottomEdge._contactToEdit |
1452 | + bottomEdge._contactToEdit = null |
1453 | + } |
1454 | + |
1455 | + onCollapseCompleted: { |
1456 | + _realPage = editorPageBottomEdge.createObject(null) |
1457 | + } |
1458 | + |
1459 | + Component.onCompleted: { |
1460 | + _realPage = editorPageBottomEdge.createObject(null) |
1461 | + } |
1462 | + |
1463 | + Component { |
1464 | + id: editorPageBottomEdge |
1465 | + |
1466 | + ABContactEditorPage { |
1467 | + implicitWidth: bottomEdge.width |
1468 | + implicitHeight: bottomEdge.height |
1469 | + contact: ContactsUI.ContactsJS.createEmptyContact("", bottomEdge) |
1470 | + model: bottomEdge.modelToEdit |
1471 | + enabled: bottomEdge.status === BottomEdge.Committed |
1472 | + active: bottomEdge.status === BottomEdge.Committed |
1473 | + visible: bottomEdge.status !== BottomEdge.Hidden |
1474 | + onCanceled: bottomEdge.collapse() |
1475 | + onContactSaved: bottomEdge.collapse() |
1476 | + pageStack: bottomEdge.pageStack |
1477 | + } |
1478 | + } |
1479 | +} |
1480 | |
1481 | === removed file 'src/imports/BottomEdge.qml' |
1482 | --- src/imports/BottomEdge.qml 2015-12-14 15:31:50 +0000 |
1483 | +++ src/imports/BottomEdge.qml 1970-01-01 00:00:00 +0000 |
1484 | @@ -1,338 +0,0 @@ |
1485 | -/* |
1486 | - * Copyright (C) 2015 Canonical, Ltd. |
1487 | - * |
1488 | - * This program is free software; you can redistribute it and/or modify |
1489 | - * it under the terms of the GNU General Public License as published by |
1490 | - * the Free Software Foundation; version 3. |
1491 | - * |
1492 | - * This program is distributed in the hope that it will be useful, |
1493 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1494 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1495 | - * GNU General Public License for more details. |
1496 | - * |
1497 | - * You should have received a copy of the GNU General Public License |
1498 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1499 | - */ |
1500 | - |
1501 | -import QtQuick 2.4 |
1502 | -import Ubuntu.Components 1.3 |
1503 | - |
1504 | -Item { |
1505 | - id: bottomEdge |
1506 | - |
1507 | - readonly property alias content: bottomEdgeLoader.item |
1508 | - readonly property bool fullLoaded: bottomEdgeLoader.status == Loader.Ready |
1509 | - |
1510 | - property bool opened: false |
1511 | - property Component contentComponent |
1512 | - property string iconName |
1513 | - property Item flickable |
1514 | - property alias backGroundEffectEnabled: darkBg.visible |
1515 | - |
1516 | - signal openBegin |
1517 | - signal openEnd |
1518 | - signal clicked |
1519 | - signal bottomEdgeLoaded |
1520 | - |
1521 | - function open() { |
1522 | - bottomEdge.state = "expanded"; |
1523 | - } |
1524 | - |
1525 | - function close() { |
1526 | - bottomEdge.state = "collapsed"; |
1527 | - } |
1528 | - |
1529 | - Action { |
1530 | - text: i18n.tr("New contact") |
1531 | - enabled: bottomEdge.visible |
1532 | - shortcut: "Ctrl+N" |
1533 | - onTriggered: bottomEdge.clicked() |
1534 | - } |
1535 | - |
1536 | - Rectangle { |
1537 | - id: darkBg |
1538 | - |
1539 | - anchors.fill: parent |
1540 | - color: "black" |
1541 | - opacity: 0.0 |
1542 | - } |
1543 | - |
1544 | - Item { |
1545 | - id: bottomEdgeBody |
1546 | - anchors { |
1547 | - left: parent.left |
1548 | - right: parent.right |
1549 | - } |
1550 | - height: bottomEdgeContent.height |
1551 | - |
1552 | - Item { |
1553 | - id: bottomEdgeContent |
1554 | - anchors { |
1555 | - left: parent.left |
1556 | - right: parent.right |
1557 | - } |
1558 | - height: bottomEdgeLoader.height |
1559 | - |
1560 | - Item { |
1561 | - id: bottomEdgeShadows |
1562 | - anchors.fill: bottomEdgeContent |
1563 | - |
1564 | - BottomEdgeShadow { |
1565 | - anchors.bottom: parent.top |
1566 | - } |
1567 | - |
1568 | - BottomEdgeShadow { |
1569 | - anchors.top: parent.bottom |
1570 | - rotation: 180 |
1571 | - } |
1572 | - } |
1573 | - |
1574 | - Rectangle { |
1575 | - anchors.fill: parent |
1576 | - color: Theme.palette.normal.background |
1577 | - } |
1578 | - |
1579 | - Loader { |
1580 | - id: bottomEdgeLoader |
1581 | - sourceComponent: bottomEdge.contentComponent |
1582 | - asynchronous: true |
1583 | - active: bottomEdge.enabled |
1584 | - onStatusChanged: { |
1585 | - if (status === Loader.Ready) |
1586 | - bottomEdge.bottomEdgeLoaded() |
1587 | - } |
1588 | - } |
1589 | - } |
1590 | - |
1591 | - BottomEdgeHint { |
1592 | - id: bottomEdgeHint |
1593 | - |
1594 | - anchors.bottom: bottomEdgeBody.top |
1595 | - iconName: bottomEdge.iconName |
1596 | - onClicked: bottomEdge.clicked() |
1597 | - |
1598 | - Connections { |
1599 | - target: bottomEdgeDragArea |
1600 | - onClosedChanged: { |
1601 | - if (!bottomEdgeDragArea.closed) { |
1602 | - bottomEdgeHint.state = "Visible"; |
1603 | - } |
1604 | - } |
1605 | - } |
1606 | - |
1607 | - Connections { |
1608 | - target: flickable |
1609 | - onVerticalVelocityChanged: { |
1610 | - if (!bottomEdgeDragArea.closed) { |
1611 | - return; |
1612 | - } |
1613 | - |
1614 | - if (flickable.verticalVelocity > 0) { |
1615 | - bottomEdgeHint.state = "Hidden"; |
1616 | - } else if (flickable.verticalVelocity < 0) { |
1617 | - bottomEdgeHint.state = "Visible"; |
1618 | - } |
1619 | - } |
1620 | - } |
1621 | - } |
1622 | - } |
1623 | - |
1624 | - |
1625 | - state: "collapsed" |
1626 | - states: [ |
1627 | - State { |
1628 | - name: "collapsed" |
1629 | - ParentChange { |
1630 | - target: bottomEdgeContent |
1631 | - parent: bottomEdgeBody |
1632 | - x: 0 |
1633 | - y: 0 |
1634 | - } |
1635 | - PropertyChanges { |
1636 | - target: bottomEdgeBody |
1637 | - y: bottomEdgeDragArea.drag.maximumY |
1638 | - } |
1639 | - PropertyChanges { |
1640 | - target: bottomEdgeContent |
1641 | - opacity: 0.0 |
1642 | - } |
1643 | - PropertyChanges { |
1644 | - target: darkBg |
1645 | - opacity: 0.0 |
1646 | - } |
1647 | - }, |
1648 | - State { |
1649 | - name: "expanded" |
1650 | - ParentChange { |
1651 | - target: bottomEdgeContent |
1652 | - parent: bottomEdge |
1653 | - x: 0 |
1654 | - y: 0 |
1655 | - } |
1656 | - PropertyChanges { |
1657 | - target: bottomEdgeContent |
1658 | - opacity: 1.0 |
1659 | - } |
1660 | - PropertyChanges { |
1661 | - target: bottomEdgeBody |
1662 | - y: 0 |
1663 | - } |
1664 | - PropertyChanges { |
1665 | - target: bottomEdgeShadows |
1666 | - opacity: 0.0 |
1667 | - visible: true |
1668 | - } |
1669 | - PropertyChanges { |
1670 | - target: darkBg |
1671 | - opacity: 0.8 |
1672 | - } |
1673 | - }, |
1674 | - State { |
1675 | - name: "floating" |
1676 | - when: bottomEdgeDragArea.drag.active |
1677 | - PropertyChanges { |
1678 | - target: bottomEdgeContent |
1679 | - opacity: 1.0 |
1680 | - } |
1681 | - PropertyChanges { |
1682 | - target: darkBg |
1683 | - opacity: bottomEdgeBody.y > 0 ? 0.8 - (bottomEdgeBody.y / bottomEdgeDragArea.drag.maximumY) : 0.8 |
1684 | - } |
1685 | - } |
1686 | - ] |
1687 | - |
1688 | - transitions: [ |
1689 | - Transition { |
1690 | - to: "collapsed" |
1691 | - SequentialAnimation { |
1692 | - alwaysRunToEnd: true |
1693 | - ParallelAnimation { |
1694 | - ParentAnimation { |
1695 | - UbuntuNumberAnimation { |
1696 | - properties: "x,y" |
1697 | - duration: UbuntuAnimation.SlowDuration |
1698 | - target: bottomEdgeContent |
1699 | - } |
1700 | - } |
1701 | - UbuntuNumberAnimation { |
1702 | - target: bottomEdgeBody |
1703 | - property: "y" |
1704 | - duration: UbuntuAnimation.SlowDuration |
1705 | - } |
1706 | - UbuntuNumberAnimation { |
1707 | - target: darkBg |
1708 | - property: "opacity" |
1709 | - duration: UbuntuAnimation.SlowDuration |
1710 | - } |
1711 | - } |
1712 | - PropertyAction { |
1713 | - target: bottomEdgeContent |
1714 | - property: "opacity" |
1715 | - } |
1716 | - ScriptAction { |
1717 | - script: { |
1718 | - bottomEdgeLoader.active = false |
1719 | - bottomEdgeLoader.active = true |
1720 | - bottomEdge.opened = false |
1721 | - } |
1722 | - } |
1723 | - } |
1724 | - }, |
1725 | - Transition { |
1726 | - to: "expanded" |
1727 | - SequentialAnimation { |
1728 | - alwaysRunToEnd: true |
1729 | - ParallelAnimation { |
1730 | - ScriptAction { |
1731 | - script: bottomEdge.openBegin() |
1732 | - } |
1733 | - ParentAnimation { |
1734 | - UbuntuNumberAnimation { |
1735 | - properties: "x,y" |
1736 | - duration: UbuntuAnimation.SlowDuration |
1737 | - target: bottomEdgeContent |
1738 | - } |
1739 | - } |
1740 | - UbuntuNumberAnimation { |
1741 | - target: bottomEdgeShadows |
1742 | - property: "opacity" |
1743 | - duration: UbuntuAnimation.SlowDuration |
1744 | - } |
1745 | - UbuntuNumberAnimation { |
1746 | - target: darkBg |
1747 | - property: "opacity" |
1748 | - duration: UbuntuAnimation.SlowDuration |
1749 | - } |
1750 | - } |
1751 | - UbuntuNumberAnimation { |
1752 | - target: bottomEdgeContent |
1753 | - property: "opacity" |
1754 | - duration: UbuntuAnimation.FastDuration |
1755 | - } |
1756 | - ScriptAction { |
1757 | - script: { |
1758 | - bottomEdge.opened = true |
1759 | - bottomEdge.openEnd() |
1760 | - } |
1761 | - |
1762 | - } |
1763 | - } |
1764 | - } |
1765 | - ] |
1766 | - |
1767 | - MouseArea { |
1768 | - id: bottomEdgeDragArea |
1769 | - objectName: "bottomEdgeDragArea" |
1770 | - |
1771 | - property real previousY: -1 |
1772 | - property string dragDirection: "None" |
1773 | - property bool closed: drag.target.y == bottomEdgeDragArea.drag.maximumY |
1774 | - && !bottomEdgeDragArea.pressed |
1775 | - |
1776 | - preventStealing: true |
1777 | - propagateComposedEvents: true |
1778 | - drag { |
1779 | - axis: Drag.YAxis |
1780 | - target: bottomEdgeBody |
1781 | - minimumY: 0 |
1782 | - maximumY: bottomEdge.height |
1783 | - } |
1784 | - |
1785 | - anchors { |
1786 | - left: parent.left |
1787 | - right: parent.right |
1788 | - bottom: parent.bottom |
1789 | - } |
1790 | - height: bottomEdgeHint.height |
1791 | - |
1792 | - onPressed: { |
1793 | - previousY = mouse.y; |
1794 | - } |
1795 | - |
1796 | - onReleased: { |
1797 | - if (dragDirection === "BottomToTop") { |
1798 | - bottomEdge.state = "expanded"; |
1799 | - } else { |
1800 | - bottomEdge.state = "collapsed"; |
1801 | - } |
1802 | - previousY = -1; |
1803 | - dragDirection = "None"; |
1804 | - } |
1805 | - |
1806 | - onMouseYChanged: { |
1807 | - var yOffset = previousY - mouseY; |
1808 | - // skip if was a small move |
1809 | - if (Math.abs(yOffset) <= units.gu(2)) { |
1810 | - return; |
1811 | - } |
1812 | - previousY = mouseY; |
1813 | - dragDirection = yOffset > 0 ? "BottomToTop" : "TopToBottom"; |
1814 | - } |
1815 | - } |
1816 | - |
1817 | - Binding { |
1818 | - target: bottomEdge |
1819 | - property: 'visible' |
1820 | - value: bottomEdge.enabled && !bottomEdge.opened |
1821 | - } |
1822 | -} |
1823 | |
1824 | === removed file 'src/imports/BottomEdgeShadow.qml' |
1825 | --- src/imports/BottomEdgeShadow.qml 2015-09-10 14:47:38 +0000 |
1826 | +++ src/imports/BottomEdgeShadow.qml 1970-01-01 00:00:00 +0000 |
1827 | @@ -1,31 +0,0 @@ |
1828 | -/* |
1829 | - * Copyright (C) 2015 Canonical, Ltd. |
1830 | - * |
1831 | - * This program is free software; you can redistribute it and/or modify |
1832 | - * it under the terms of the GNU General Public License as published by |
1833 | - * the Free Software Foundation; version 3. |
1834 | - * |
1835 | - * This program is distributed in the hope that it will be useful, |
1836 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1837 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1838 | - * GNU General Public License for more details. |
1839 | - * |
1840 | - * You should have received a copy of the GNU General Public License |
1841 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1842 | - */ |
1843 | - |
1844 | -import QtQuick 2.4 |
1845 | -import Ubuntu.Components 1.3 |
1846 | - |
1847 | -Rectangle { |
1848 | - id: bottomEdgeShadow |
1849 | - anchors { |
1850 | - left: parent.left |
1851 | - right: parent.right |
1852 | - } |
1853 | - height: units.gu(1) |
1854 | - gradient: Gradient { |
1855 | - GradientStop { position: 0.0; color: Qt.rgba(0.0, 0.0, 0.0, 0.0) } |
1856 | - GradientStop { position: 1.0; color: Qt.rgba(0.0, 0.0, 0.0, 0.3) } |
1857 | - } |
1858 | -} |
1859 | |
1860 | === modified file 'src/imports/CMakeLists.txt' |
1861 | --- src/imports/CMakeLists.txt 2015-11-19 14:41:18 +0000 |
1862 | +++ src/imports/CMakeLists.txt 2016-01-07 13:19:12 +0000 |
1863 | @@ -4,10 +4,11 @@ |
1864 | ABContactListPage.qml |
1865 | ABContactEditorPage.qml |
1866 | ABContactViewPage.qml |
1867 | + ABEmptyState.qml |
1868 | + ABNewContactBottomEdge.qml |
1869 | + ABMultiColumnEmptyState.qml |
1870 | ContentHubProxy.qml |
1871 | MainWindow.qml |
1872 | - BottomEdgeShadow.qml |
1873 | - BottomEdge.qml |
1874 | ) |
1875 | |
1876 | install(FILES ${ADDRESS_BOOK_APP_QMLS} |
1877 | |
1878 | === modified file 'src/imports/MainWindow.qml' |
1879 | --- src/imports/MainWindow.qml 2015-12-10 19:13:20 +0000 |
1880 | +++ src/imports/MainWindow.qml 2016-01-07 13:19:12 +0000 |
1881 | @@ -18,6 +18,8 @@ |
1882 | import Ubuntu.Components 1.3 |
1883 | import Ubuntu.Components.Popups 1.3 as Popups |
1884 | |
1885 | +import Unity.InputInfo 0.1 |
1886 | + |
1887 | MainView { |
1888 | id: mainWindow |
1889 | objectName: "addressBookAppMainWindow" |
1890 | @@ -47,16 +49,6 @@ |
1891 | } |
1892 | } |
1893 | |
1894 | - function addphone(contactId, phoneNumber) |
1895 | - { |
1896 | - mainStack.resetStack() |
1897 | - if (mainStack.contactListPage) { |
1898 | - mainStack.contactListPage.addPhoneToContact(contactId, phoneNumber) |
1899 | - } else { |
1900 | - console.error("Add phone to contact requested but ContactListPage not loaded") |
1901 | - } |
1902 | - } |
1903 | - |
1904 | function pick(single) |
1905 | { |
1906 | console.debug("Pick mode:" + single) |
1907 | @@ -88,24 +80,35 @@ |
1908 | } |
1909 | } |
1910 | |
1911 | - function addnewphone(phoneNumer) |
1912 | - { |
1913 | - mainStack.resetStack() |
1914 | - if (mainStack.contactListPage) { |
1915 | - mainStack.contactListPage.addNewPhone(phoneNumer) |
1916 | - } else { |
1917 | - console.error("Add new phone requested but ContactListPage not loaded") |
1918 | - } |
1919 | - } |
1920 | - |
1921 | width: units.gu(90) |
1922 | height: units.gu(71) |
1923 | anchorToKeyboard: false |
1924 | |
1925 | + InputDeviceModel { |
1926 | + id: miceModel |
1927 | + deviceFilter: InputInfo.Mouse |
1928 | + } |
1929 | + |
1930 | + InputDeviceModel { |
1931 | + id: touchPadModel |
1932 | + deviceFilter: InputInfo.TouchPad |
1933 | + } |
1934 | + |
1935 | + InputDeviceModel { |
1936 | + id: keyboardsModel |
1937 | + deviceFilter: InputInfo.Keyboard |
1938 | + } |
1939 | + |
1940 | + |
1941 | AdaptivePageLayout { |
1942 | id: mainStack |
1943 | + objectName: "mainStack" |
1944 | |
1945 | property var contactListPage: null |
1946 | + property var bottomEdge: null |
1947 | + readonly property bool bottomEdgeOpened: (bottomEdge && bottomEdge.status === BottomEdge.Committed) |
1948 | + readonly property bool hasMouse: ((miceModel.count > 0) || (touchPadModel.count > 0)) |
1949 | + readonly property bool hasKeyboard: (keyboardsModel.count > 0) |
1950 | |
1951 | function resetStack() |
1952 | { |
1953 | @@ -145,7 +148,7 @@ |
1954 | anchors.fill: parent |
1955 | layouts: [ |
1956 | PageColumnsLayout { |
1957 | - when: mainStack.width >= units.gu(80) |
1958 | + when: mainStack.width >= units.gu(70) |
1959 | PageColumn { |
1960 | maximumWidth: units.gu(50) |
1961 | minimumWidth: units.gu(40) |
1962 | @@ -163,6 +166,14 @@ |
1963 | } |
1964 | ] |
1965 | |
1966 | + onColumnsChanged: { |
1967 | + if (mainStack.columns > 1) { |
1968 | + if (mainStack.contactListPage) |
1969 | + mainStack.contactListPage.fetchContact() |
1970 | + else |
1971 | + mainStack.addPageToNextColumn(contactPage, Qt.resolvedUrl("./ABMultiColumnEmptyState.qml")) |
1972 | + } |
1973 | + } |
1974 | } |
1975 | |
1976 | ABContactListPage { |
1977 | @@ -177,6 +188,16 @@ |
1978 | mainWindow.applicationReady() |
1979 | } |
1980 | |
1981 | + // WORKAROUND: Due the missing feature on SDK, they can not detect if |
1982 | + // there is a mouse attached to device or not. And this will cause the |
1983 | + // bootom edge component to not work correct on desktop. |
1984 | + // We will consider that a mouse is always attached until it get implement on SDK. |
1985 | + Binding { |
1986 | + target: QuickUtils |
1987 | + property: "mouseAttached" |
1988 | + value: mainStack.hasMouse |
1989 | + } |
1990 | + |
1991 | Component { |
1992 | id: errorDialog |
1993 | |
1994 | |
1995 | === modified file 'src/imports/Settings/SettingsPage.qml' |
1996 | --- src/imports/Settings/SettingsPage.qml 2015-12-16 18:35:33 +0000 |
1997 | +++ src/imports/Settings/SettingsPage.qml 2016-01-07 13:19:12 +0000 |
1998 | @@ -87,12 +87,12 @@ |
1999 | // FIXME: Using a private property here. This uses the old list item and the only way to change the text |
2000 | // color is with this property. |
2001 | // We should remove it when update the app to the new ListItem. |
2002 | - __foregroundColor: (activeFocus && (pageStack.columns > 1)) ? Theme.palette.normal.foregroundText : |
2003 | - Theme.palette.normal.foreground |
2004 | + __foregroundColor: (activeFocus && pageStack.hasKeyboard) ? Theme.palette.normal.foregroundText : |
2005 | + Theme.palette.normal.foreground |
2006 | Rectangle { |
2007 | color: UbuntuColors.orange |
2008 | anchors.fill: parent |
2009 | - visible:addGoogleAccountItem.activeFocus |
2010 | + visible:addGoogleAccountItem.activeFocus && pageStack.hasKeyboard |
2011 | z: -1 |
2012 | } |
2013 | } |
2014 | |
2015 | === modified file 'src/imports/Ubuntu/AddressBook/Base/ContactDetailGroupBase.qml' |
2016 | --- src/imports/Ubuntu/AddressBook/Base/ContactDetailGroupBase.qml 2015-11-19 16:38:36 +0000 |
2017 | +++ src/imports/Ubuntu/AddressBook/Base/ContactDetailGroupBase.qml 2016-01-07 13:19:12 +0000 |
2018 | @@ -33,9 +33,8 @@ |
2019 | property int minimumHeight: 0 |
2020 | property bool loaded: false |
2021 | property bool showEmpty: true |
2022 | - property bool forceFocusOnFieldCreation: false |
2023 | |
2024 | - signal newFieldAdded(var index) |
2025 | + signal newFieldAdded(int fieldIndex, QtObject field) |
2026 | |
2027 | function reloadDetails(clearFields) |
2028 | { |
2029 | @@ -145,10 +144,10 @@ |
2030 | if (status === Loader.Ready) { |
2031 | var newFields = root.inputFields |
2032 | newFields.push(detailItem.item) |
2033 | - root.newFieldAdded(detailItem.item) |
2034 | + |
2035 | root.inputFields = newFields |
2036 | - if (root.loaded && root.forceFocusOnFieldCreation) { |
2037 | - item.forceActiveFocus() |
2038 | + if (root.loaded) { |
2039 | + root.newFieldAdded(detailItem.item, item) |
2040 | } |
2041 | } |
2042 | } |
2043 | |
2044 | === modified file 'src/imports/Ubuntu/AddressBook/Base/KeyboardRectangle.qml' |
2045 | --- src/imports/Ubuntu/AddressBook/Base/KeyboardRectangle.qml 2015-10-26 13:18:11 +0000 |
2046 | +++ src/imports/Ubuntu/AddressBook/Base/KeyboardRectangle.qml 2016-01-07 13:19:12 +0000 |
2047 | @@ -18,10 +18,13 @@ |
2048 | |
2049 | Item { |
2050 | id: keyboardRect |
2051 | + |
2052 | + property bool active: true |
2053 | + |
2054 | anchors.left: parent.left |
2055 | anchors.right: parent.right |
2056 | anchors.bottom: parent.bottom |
2057 | - height: Qt.inputMethod.visible ? Qt.inputMethod.keyboardRectangle.height : 0 |
2058 | + height: active && Qt.inputMethod.visible ? Qt.inputMethod.keyboardRectangle.height : 0 |
2059 | |
2060 | states: [ |
2061 | State { |
2062 | |
2063 | === modified file 'src/imports/Ubuntu/AddressBook/ContactEditor/ComboButtonAddField.qml' |
2064 | --- src/imports/Ubuntu/AddressBook/ContactEditor/ComboButtonAddField.qml 2015-10-26 13:18:11 +0000 |
2065 | +++ src/imports/Ubuntu/AddressBook/ContactEditor/ComboButtonAddField.qml 2016-01-07 13:19:12 +0000 |
2066 | @@ -106,8 +106,8 @@ |
2067 | // make sure that the signal will be fired after the item collapse |
2068 | onHeightChanged: { |
2069 | if (!expanded && (selectedDetail !== -1) && (height === collapsedHeight)) { |
2070 | - fieldSelected(root.nameFromEnum(selectedDetail), root.qmlTypeFromEnum(selectedDetail)) |
2071 | - selectedDetail = -1 |
2072 | + root.fieldSelected(root.nameFromEnum(root.selectedDetail), root.qmlTypeFromEnum(root.selectedDetail)) |
2073 | + root.selectedDetail = -1 |
2074 | } |
2075 | } |
2076 | |
2077 | |
2078 | === modified file 'src/imports/Ubuntu/AddressBook/ContactEditor/ContactDetailAvatarEditor.qml' |
2079 | --- src/imports/Ubuntu/AddressBook/ContactEditor/ContactDetailAvatarEditor.qml 2015-11-24 12:18:17 +0000 |
2080 | +++ src/imports/Ubuntu/AddressBook/ContactEditor/ContactDetailAvatarEditor.qml 2016-01-07 13:19:12 +0000 |
2081 | @@ -144,7 +144,6 @@ |
2082 | } |
2083 | |
2084 | Component.onDestruction: { |
2085 | - console.debug("Delete temporary avatar image:" + root.temporaryAvatar) |
2086 | Contacts.removeFile("file:///" + root.temporaryAvatar) |
2087 | root.temporaryAvatar = "" |
2088 | } |
2089 | |
2090 | === modified file 'src/imports/Ubuntu/AddressBook/ContactEditor/ContactDetailGroupWithTypeEditor.qml' |
2091 | --- src/imports/Ubuntu/AddressBook/ContactEditor/ContactDetailGroupWithTypeEditor.qml 2015-11-19 16:38:36 +0000 |
2092 | +++ src/imports/Ubuntu/AddressBook/ContactEditor/ContactDetailGroupWithTypeEditor.qml 2016-01-07 13:19:12 +0000 |
2093 | @@ -98,7 +98,6 @@ |
2094 | return changed |
2095 | } |
2096 | |
2097 | - forceFocusOnFieldCreation: true |
2098 | headerDelegate: Label { |
2099 | id: header |
2100 | |
2101 | |
2102 | === modified file 'src/imports/Ubuntu/AddressBook/ContactEditor/ContactDetailWithTypeEditor.qml' |
2103 | --- src/imports/Ubuntu/AddressBook/ContactEditor/ContactDetailWithTypeEditor.qml 2015-11-10 19:03:36 +0000 |
2104 | +++ src/imports/Ubuntu/AddressBook/ContactEditor/ContactDetailWithTypeEditor.qml 2016-01-07 13:19:12 +0000 |
2105 | @@ -33,6 +33,7 @@ |
2106 | property variant placeholderTexts: [] |
2107 | property int inputMethodHints: Qt.ImhNone |
2108 | property bool usePhoneFormat: false |
2109 | + readonly property alias repeater: fieldRepeater |
2110 | |
2111 | function selectType(type) { |
2112 | detailTypeSelector.selectItem(type) |
2113 | @@ -96,7 +97,6 @@ |
2114 | |
2115 | detail: root.detail |
2116 | field: modelData |
2117 | - focus: true |
2118 | placeholderText: root.placeholderTexts[index] |
2119 | inputMethodHints: root.inputMethodHints |
2120 | autoFormat: root.usePhoneFormat |
2121 | |
2122 | === modified file 'src/imports/Ubuntu/AddressBook/ContactEditor/ContactEditorPage.qml' |
2123 | --- src/imports/Ubuntu/AddressBook/ContactEditor/ContactEditorPage.qml 2015-12-18 13:16:55 +0000 |
2124 | +++ src/imports/Ubuntu/AddressBook/ContactEditor/ContactEditorPage.qml 2016-01-07 13:19:12 +0000 |
2125 | @@ -33,11 +33,15 @@ |
2126 | |
2127 | property string initialFocusSection: "" |
2128 | property var newDetails: [] |
2129 | + property list<QtObject> leadingActions |
2130 | + property alias headerActions: trailingBar.actions |
2131 | |
2132 | readonly property bool isNewContact: contact && (contact.contactId === "qtcontacts:::") |
2133 | readonly property bool isContactValid: !avatarEditor.busy && (!nameEditor.isEmpty() || !phonesEditor.isEmpty()) |
2134 | + readonly property alias editorFlickable: scrollArea |
2135 | |
2136 | signal contactSaved(var contact); |
2137 | + signal canceled() |
2138 | |
2139 | function cancel() { |
2140 | for (var i = 0; i < contactEditor.newDetails.length; ++i) { |
2141 | @@ -51,11 +55,12 @@ |
2142 | field.cancel() |
2143 | } |
2144 | } |
2145 | - if (pageStack.removePages) { |
2146 | + if (pageStack && pageStack.removePages) { |
2147 | pageStack.removePages(contactEditor) |
2148 | - } else { |
2149 | + } else if (pageStack) { |
2150 | pageStack.pop() |
2151 | } |
2152 | + contactEditor.canceled() |
2153 | } |
2154 | |
2155 | function save() { |
2156 | @@ -100,18 +105,25 @@ |
2157 | } |
2158 | } |
2159 | |
2160 | - function makeMeVisible(item) { |
2161 | + function idleMakeMeVisible(item) { |
2162 | if (!enabled || !item) { |
2163 | return |
2164 | } |
2165 | |
2166 | activeItem = item |
2167 | - var position = scrollArea.contentItem.mapFromItem(item, 0, activeItem.y); |
2168 | - |
2169 | + timerMakemakeMeVisible.restart() |
2170 | + } |
2171 | + |
2172 | + function makeMeVisible(item) { |
2173 | + if (!item) |
2174 | + return |
2175 | + |
2176 | + var position = activeItem.mapToItem(editEditor, item.x, item.y); |
2177 | // check if the item is already visible |
2178 | var bottomY = scrollArea.contentY + scrollArea.height |
2179 | var itemBottom = position.y + (item.height * 3) // extra margin |
2180 | if (position.y >= scrollArea.contentY && itemBottom <= bottomY) { |
2181 | + Qt.inputMethod.show() |
2182 | return; |
2183 | } |
2184 | |
2185 | @@ -123,7 +135,9 @@ |
2186 | // if it is hidden at the top, also show it |
2187 | scrollArea.contentY = position.y; |
2188 | } |
2189 | + |
2190 | scrollArea.returnToBounds() |
2191 | + Qt.inputMethod.show() |
2192 | } |
2193 | |
2194 | function ready() |
2195 | @@ -135,6 +149,7 @@ |
2196 | contactEditor.focusToLastPhoneField() |
2197 | break; |
2198 | case "name": |
2199 | + default: |
2200 | nameEditor.fieldDelegates[0].forceActiveFocus() |
2201 | break; |
2202 | } |
2203 | @@ -146,9 +161,42 @@ |
2204 | lastPhoneField.forceActiveFocus() |
2205 | } |
2206 | |
2207 | - title: isNewContact ? i18n.dtr("address-book-app", "New contact") : i18n.dtr("address-book-app", "Edit") |
2208 | + function focusToFirstEntry(field) |
2209 | + { |
2210 | + var itemToFocus = field |
2211 | + if (field.repeater) |
2212 | + itemToFocus = field.repeater.itemAt(0) |
2213 | + |
2214 | + if (itemToFocus) { |
2215 | + root.idleMakeMeVisible(itemToFocus) |
2216 | + itemToFocus.forceActiveFocus() |
2217 | + } |
2218 | + } |
2219 | + |
2220 | + Timer { |
2221 | + id: timerMakemakeMeVisible |
2222 | + |
2223 | + interval: 100 |
2224 | + repeat: false |
2225 | + running: false |
2226 | + onTriggered: root.makeMeVisible(root.activeItem) |
2227 | + } |
2228 | + |
2229 | + header: PageHeader { |
2230 | + id: pageHeader |
2231 | + |
2232 | + title: isNewContact ? i18n.dtr("address-book-app", "New contact") : i18n.dtr("address-book-app", "Edit") |
2233 | + trailingActionBar { |
2234 | + id: trailingBar |
2235 | + } |
2236 | + leadingActionBar { |
2237 | + id: leadingBar |
2238 | + actions: contactEditor.leadingActions |
2239 | + } |
2240 | + } |
2241 | + |
2242 | enabled: false |
2243 | - |
2244 | + flickable: null |
2245 | Timer { |
2246 | id: focusTimer |
2247 | |
2248 | @@ -158,7 +206,6 @@ |
2249 | onTriggered: contactEditor.ready() |
2250 | } |
2251 | |
2252 | - flickable: null |
2253 | Flickable { |
2254 | id: scrollArea |
2255 | objectName: "scrollArea" |
2256 | @@ -169,17 +216,13 @@ |
2257 | anchors{ |
2258 | left: parent.left |
2259 | top: parent.top |
2260 | + topMargin: pageHeader.height |
2261 | right: parent.right |
2262 | bottom: keyboardRectangle.top |
2263 | } |
2264 | contentHeight: contents.height + units.gu(2) |
2265 | contentWidth: parent.width |
2266 | |
2267 | - //after add a new field we need to wait for the contentHeight to change to scroll to the correct position |
2268 | - onContentHeightChanged: { |
2269 | - contactEditor.makeMeVisible(contactEditor.activeItem) |
2270 | - } |
2271 | - |
2272 | Column { |
2273 | id: contents |
2274 | |
2275 | @@ -242,6 +285,7 @@ |
2276 | right: parent.right |
2277 | } |
2278 | height: implicitHeight |
2279 | + onNewFieldAdded: root.focusToFirstEntry(field) |
2280 | } |
2281 | |
2282 | ContactDetailEmailsEditor { |
2283 | @@ -254,6 +298,7 @@ |
2284 | right: parent.right |
2285 | } |
2286 | height: implicitHeight |
2287 | + onNewFieldAdded: root.focusToFirstEntry(field) |
2288 | } |
2289 | |
2290 | ContactDetailOnlineAccountsEditor { |
2291 | @@ -266,6 +311,7 @@ |
2292 | right: parent.right |
2293 | } |
2294 | height: implicitHeight |
2295 | + onNewFieldAdded: root.focusToFirstEntry(field) |
2296 | } |
2297 | |
2298 | ContactDetailAddressesEditor { |
2299 | @@ -278,6 +324,7 @@ |
2300 | right: parent.right |
2301 | } |
2302 | height: implicitHeight |
2303 | + onNewFieldAdded: root.focusToFirstEntry(field) |
2304 | } |
2305 | |
2306 | ContactDetailOrganizationsEditor { |
2307 | @@ -290,6 +337,7 @@ |
2308 | right: parent.right |
2309 | } |
2310 | height: implicitHeight |
2311 | + onNewFieldAdded: root.focusToFirstEntry(field) |
2312 | } |
2313 | |
2314 | ContactDetailSyncTargetEditor { |
2315 | @@ -332,6 +380,7 @@ |
2316 | margins: units.gu(2) |
2317 | } |
2318 | height: implicitHeight |
2319 | + activeFocusOnPress: false |
2320 | onHeightChanged: { |
2321 | if (expanded && (height === expandedHeight) && !scrollArea.atYEnd) { |
2322 | moveToBottom.start() |
2323 | @@ -343,9 +392,11 @@ |
2324 | |
2325 | target: scrollArea |
2326 | property: "contentY" |
2327 | - from: scrollArea.contentY |
2328 | - to: Math.min(scrollArea.contentHeight - scrollArea.height, |
2329 | - scrollArea.contentY + (addNewFieldButton.height - addNewFieldButton.collapsedHeight - units.gu(3))) |
2330 | + to: scrollArea.contentHeight - scrollArea.height |
2331 | + onStopped: { |
2332 | + scrollArea.returnToBounds() |
2333 | + addNewFieldButton.forceActiveFocus() |
2334 | + } |
2335 | } |
2336 | |
2337 | onFieldSelected: { |
2338 | @@ -406,8 +457,11 @@ |
2339 | id: keyboardRectangle |
2340 | |
2341 | onHeightChanged: { |
2342 | - if (activeItem) { |
2343 | - makeMeVisible(activeItem) |
2344 | + if (addNewFieldButton.expanded) { |
2345 | + scrollArea.contentY = scrollArea.contentHeight - scrollArea.height |
2346 | + scrollArea.returnToBounds() |
2347 | + } else if (activeItem) { |
2348 | + idleMakeMeVisible(activeItem) |
2349 | } |
2350 | } |
2351 | } |
2352 | @@ -493,6 +547,8 @@ |
2353 | contactEditor.pageStack.pop() // view page |
2354 | } |
2355 | } |
2356 | + if (contactEditor.pageStack.primaryPage) |
2357 | + contactEditor.pageStack.primaryPage.forceActiveFocus() |
2358 | } |
2359 | } |
2360 | } |
2361 | |
2362 | === modified file 'src/imports/Ubuntu/AddressBook/ContactEditor/TextInputDetail.qml' |
2363 | --- src/imports/Ubuntu/AddressBook/ContactEditor/TextInputDetail.qml 2015-11-25 17:31:33 +0000 |
2364 | +++ src/imports/Ubuntu/AddressBook/ContactEditor/TextInputDetail.qml 2016-01-07 13:19:12 +0000 |
2365 | @@ -47,27 +47,18 @@ |
2366 | |
2367 | //FIXME: Move this property to TextField as soon as the SDK get ported to QtQuick 2.2 |
2368 | activeFocusOnTab: true |
2369 | - |
2370 | - // WORKAROUND: For some reason TextField.focus property get reset to false |
2371 | - // we need do a deep investigation on that |
2372 | - Binding { |
2373 | - target: field |
2374 | - property: "focus" |
2375 | - value: visible |
2376 | - } |
2377 | - |
2378 | - onActiveFocusChanged: { |
2379 | - if (activeFocus && field.visible) { |
2380 | - field.forceActiveFocus() |
2381 | - } |
2382 | - } |
2383 | - |
2384 | onOriginalValueChanged: { |
2385 | if (originalValue && (originalValue !== "")) { |
2386 | field.text = originalValue |
2387 | } |
2388 | } |
2389 | |
2390 | + // propage focus to text field |
2391 | + onActiveFocusChanged: { |
2392 | + if (activeFocus) |
2393 | + field.forceActiveFocus() |
2394 | + } |
2395 | + |
2396 | PhoneNumberField { |
2397 | id: field |
2398 | |
2399 | |
2400 | === modified file 'src/imports/Ubuntu/AddressBook/ContactShare/ContactSharePage.qml' |
2401 | --- src/imports/Ubuntu/AddressBook/ContactShare/ContactSharePage.qml 2015-10-26 13:18:11 +0000 |
2402 | +++ src/imports/Ubuntu/AddressBook/ContactShare/ContactSharePage.qml 2016-01-07 13:19:12 +0000 |
2403 | @@ -50,13 +50,21 @@ |
2404 | if (exporter.activeTransfer) { |
2405 | exporter.activeTransfer.state = ContentHub.ContentTransfer.Aborted |
2406 | } |
2407 | - pageStack.removePages(root) |
2408 | + if (root.pageStack.removePages) |
2409 | + root.pageStack.removePages(root) |
2410 | + else |
2411 | + root.pageStack.pop() |
2412 | } |
2413 | } |
2414 | |
2415 | ContactExporter { |
2416 | id: exporter |
2417 | |
2418 | - onDone: pageStack.removePages(root) |
2419 | + onDone: { |
2420 | + if (root.pageStack.removePages) |
2421 | + root.pageStack.removePages(root) |
2422 | + else |
2423 | + root.pageStack.pop() |
2424 | + } |
2425 | } |
2426 | } |
2427 | |
2428 | === modified file 'src/imports/Ubuntu/AddressBook/ContactView/ContactViewPage.qml' |
2429 | --- src/imports/Ubuntu/AddressBook/ContactView/ContactViewPage.qml 2015-12-10 19:13:20 +0000 |
2430 | +++ src/imports/Ubuntu/AddressBook/ContactView/ContactViewPage.qml 2016-01-07 13:19:12 +0000 |
2431 | @@ -29,6 +29,7 @@ |
2432 | property alias extensions: extensionsContents.children |
2433 | property alias model: contactFetch.model |
2434 | property alias editable: contactDetailAvatar.editable |
2435 | + property alias headerActions: trailingBar.actions |
2436 | |
2437 | signal contactFetched(QtObject contact) |
2438 | signal contactRemoved() |
2439 | @@ -41,12 +42,20 @@ |
2440 | } |
2441 | } |
2442 | |
2443 | - title: contact ? ContactsJS.formatToDisplay(contact, i18n.dtr("address-book-app", "No name")) : "" |
2444 | + header: PageHeader { |
2445 | + id: pageHeader |
2446 | + |
2447 | + flickable: flickable |
2448 | + title: contact ? ContactsJS.formatToDisplay(contact, i18n.dtr("address-book-app", "No name")) : "" |
2449 | + trailingActionBar { |
2450 | + id: trailingBar |
2451 | + } |
2452 | + } |
2453 | |
2454 | Connections { |
2455 | target: contact |
2456 | onContactChanged: { |
2457 | - root.title = ContactsJS.formatToDisplay(contact, i18n.dtr("address-book-app", "No name")) |
2458 | + pageHeader.title = ContactsJS.formatToDisplay(contact, i18n.dtr("address-book-app", "No name")) |
2459 | } |
2460 | } |
2461 | |
2462 | @@ -88,11 +97,13 @@ |
2463 | } |
2464 | } |
2465 | |
2466 | + |
2467 | Flickable { |
2468 | id: flickable |
2469 | |
2470 | flickableDirection: Flickable.VerticalFlick |
2471 | anchors.fill: parent |
2472 | + clip: true |
2473 | //WORKAROUND: There is a bug on SDK page that causes the page to appear flicked with small contents |
2474 | // see bug #1223050 |
2475 | contentHeight: Math.max(contents.height, parent.height) + units.gu(2) |
2476 | |
2477 | === modified file 'src/imports/Ubuntu/Contacts/ContactListView.qml' |
2478 | --- src/imports/Ubuntu/Contacts/ContactListView.qml 2015-12-02 17:10:53 +0000 |
2479 | +++ src/imports/Ubuntu/Contacts/ContactListView.qml 2016-01-07 13:19:12 +0000 |
2480 | @@ -202,12 +202,6 @@ |
2481 | */ |
2482 | property bool showAddNewButton: false |
2483 | /*! |
2484 | - \qmlproperty bool prepareNewContact |
2485 | - |
2486 | - This property holds if space for a draft new contact should be made available or not |
2487 | - */ |
2488 | - property bool prepareNewContact: false |
2489 | - /*! |
2490 | \qmlproperty bool showNewContact |
2491 | |
2492 | This property holds if a draft new contact should be visible or not |
2493 | @@ -407,6 +401,7 @@ |
2494 | } |
2495 | anchors.fill: parent |
2496 | |
2497 | + |
2498 | // WORKAROUND: The SDK header causes the contactY to move to a wrong postion |
2499 | // calling the positionViewAtBeginning after the list created fix that |
2500 | Timer { |
2501 | @@ -424,15 +419,18 @@ |
2502 | right: parent.right |
2503 | } |
2504 | |
2505 | - Connections { |
2506 | - target: root |
2507 | - onPrepareNewContactChanged: { |
2508 | - if (root.prepareNewContact) { |
2509 | - view.contentY = Qt.binding(function() {return -view.headerItem.height}); |
2510 | - } else { |
2511 | - view.contentY = view.contentY; |
2512 | - } |
2513 | - } |
2514 | + Binding { |
2515 | + target: view |
2516 | + property: 'contentY' |
2517 | + value: -view.headerItem.height |
2518 | + when: root.showNewContact |
2519 | + } |
2520 | + |
2521 | + Binding { |
2522 | + target: view |
2523 | + property: 'currentIndex' |
2524 | + value: -1 |
2525 | + when: root.showNewContact |
2526 | } |
2527 | |
2528 | // AddNewButton |
2529 | @@ -461,10 +459,9 @@ |
2530 | } |
2531 | } |
2532 | selected: true |
2533 | - visible: root.prepareNewContact |
2534 | - height: root.prepareNewContact ? defaultHeight : 0 |
2535 | + visible: root.showNewContact |
2536 | + height: root.showNewContact ? defaultHeight : 0 |
2537 | Behavior on height {UbuntuNumberAnimation {}} |
2538 | - opacity: root.showNewContact ? 1.0 : 0.0 |
2539 | } |
2540 | |
2541 | Column { |
2542 | |
2543 | === modified file 'src/imports/Ubuntu/Contacts/ContactSimpleListView.qml' |
2544 | --- src/imports/Ubuntu/Contacts/ContactSimpleListView.qml 2015-12-10 19:13:29 +0000 |
2545 | +++ src/imports/Ubuntu/Contacts/ContactSimpleListView.qml 2016-01-07 13:19:12 +0000 |
2546 | @@ -270,9 +270,9 @@ |
2547 | flicking: contactListView.flicking |
2548 | width: parent.width |
2549 | selected: (contactListView.multiSelectionEnabled && contactListView.isSelected(contactDelegate)) |
2550 | - || (contactListView.highlightSelected && (contactListView.currentIndex == index)) |
2551 | - selectedColor: contactListView.parent.activeFocus && !contactListView.isInSelectionMode ? UbuntuColors.orange : |
2552 | - Theme.palette.selected.background |
2553 | + || (!contactListView.isInSelectionMode && contactListView.highlightSelected && (contactListView.currentIndex == index)) |
2554 | + selectedColor: contactListView.parent.activeFocus && !contactListView.isInSelectionMode && contactListView.highlightSelected ? |
2555 | + UbuntuColors.orange : Theme.palette.selected.background |
2556 | selectionMode: contactListView.isInSelectionMode |
2557 | defaultAvatarUrl: contactListView.defaultAvatarImageUrl |
2558 | isCurrentItem: ListView.isCurrentItem |
2559 | |
2560 | === modified file 'src/imports/Ubuntu/Contacts/ListItemWithActions.qml' |
2561 | --- src/imports/Ubuntu/Contacts/ListItemWithActions.qml 2015-11-10 19:51:19 +0000 |
2562 | +++ src/imports/Ubuntu/Contacts/ListItemWithActions.qml 2016-01-07 13:19:12 +0000 |
2563 | @@ -314,6 +314,23 @@ |
2564 | } |
2565 | |
2566 | SequentialAnimation { |
2567 | + id: clickAnimation |
2568 | + |
2569 | + running: false |
2570 | + alwaysRunToEnd: true |
2571 | + PropertyAnimation { |
2572 | + target: main |
2573 | + property: "color" |
2574 | + to: root.selectedColor |
2575 | + } |
2576 | + PropertyAction { |
2577 | + target: main |
2578 | + property: "color" |
2579 | + value: root.selected ? root.selectedColor : root.color |
2580 | + } |
2581 | + } |
2582 | + |
2583 | + SequentialAnimation { |
2584 | id: triggerAction |
2585 | |
2586 | property var currentItem: root.activeItem ? root.activeItem.image : null |
2587 | @@ -424,6 +441,8 @@ |
2588 | onClicked: { |
2589 | if (main.x === 0) { |
2590 | root.itemClicked(mouse) |
2591 | + if (!root.selected) |
2592 | + clickAnimation.start() |
2593 | } else if (main.x > 0) { |
2594 | var action = getActionAt(Qt.point(mouse.x, mouse.y)) |
2595 | if (action && action !== -1) { |
2596 | |
2597 | === modified file 'tests/autopilot/address_book_app/__init__.py' |
2598 | --- tests/autopilot/address_book_app/__init__.py 2015-10-28 13:27:33 +0000 |
2599 | +++ tests/autopilot/address_book_app/__init__.py 2016-01-07 13:19:12 +0000 |
2600 | @@ -125,14 +125,13 @@ |
2601 | return None |
2602 | |
2603 | def click_action_button(self, action_name): |
2604 | - actionbars = self.select_many('ActionBar', objectName='headerActionBar') |
2605 | - for actionbar in actionbars: |
2606 | - try: |
2607 | - actionbar.click_action_button(action_name) |
2608 | - return |
2609 | - except ubuntuuitoolkit.ToolkitException: |
2610 | - continue |
2611 | - raise exceptions.StateNotFoundError('Action %s not found.' % action_name) |
2612 | + actions = self.select_many(objectName='%s_button'%action_name) |
2613 | + for action in actions: |
2614 | + if action.enabled: |
2615 | + self.pointing_device.click_object(action) |
2616 | + return |
2617 | + |
2618 | + raise exceptions.StateNotFoundError(action_name) |
2619 | |
2620 | def open_header(self): |
2621 | header = self.get_header() |
2622 | @@ -155,6 +154,25 @@ |
2623 | |
2624 | return header |
2625 | |
2626 | + def wait_bottom_edge(self, opened): |
2627 | + # wait bottom edge to fully appear |
2628 | + mainStack = self.wait_select_single(objectName='mainStack') |
2629 | + mainStack.bottomEdgeOpened.wait_for(opened) |
2630 | + |
2631 | + def reveal_bottom_edge_page(self): |
2632 | + flickable = self.get_contact_list_view() |
2633 | + |
2634 | + globalRect = flickable.globalRect |
2635 | + start_x = globalRect.x + (globalRect.width * 0.5) |
2636 | + start_y = globalRect.y + (flickable.height * 0.98) |
2637 | + stop_y = globalRect.y + (flickable.height * 0.4) |
2638 | + |
2639 | + self.pointing_device.drag( |
2640 | + start_x, start_y, start_x, stop_y, rate=5) |
2641 | + |
2642 | + # wait bottom edge to fully appear |
2643 | + self.wait_bottom_edge(True) |
2644 | + |
2645 | def cancel(self): |
2646 | """ |
2647 | Press the 'Cancel' button |
2648 | @@ -165,6 +183,7 @@ |
2649 | self.pointing_device.click_object(button) |
2650 | return |
2651 | |
2652 | + self.click_action_button('cancel') |
2653 | #self.click_action_button("customBackButton") |
2654 | |
2655 | def save(self): |
2656 | @@ -200,7 +219,6 @@ |
2657 | """ |
2658 | Press the 'Add' button and return the contact editor page |
2659 | """ |
2660 | - bottom_swipe_page = self.get_contact_list_page() |
2661 | - bottom_swipe_page.reveal_bottom_edge_page() |
2662 | + self.reveal_bottom_edge_page() |
2663 | |
2664 | return self.get_contact_edit_page() |
2665 | |
2666 | === modified file 'tests/autopilot/address_book_app/pages/_ab_contact_list_page.py' |
2667 | --- tests/autopilot/address_book_app/pages/_ab_contact_list_page.py 2015-10-20 03:38:07 +0000 |
2668 | +++ tests/autopilot/address_book_app/pages/_ab_contact_list_page.py 2016-01-07 13:19:12 +0000 |
2669 | @@ -112,7 +112,7 @@ |
2670 | @log_action_info |
2671 | def delete_selected_contacts(self, main_window): |
2672 | main_window.delete() |
2673 | - self.bottomEdgePageOpened.wait_for(False) |
2674 | + main_window.wait_bottom_edge(False) |
2675 | dialog = self.get_root_instance().wait_select_single( |
2676 | address_book.RemoveContactsDialog, objectName='removeContactsDialog') |
2677 | dialog.confirm_removal() |
2678 | @@ -137,21 +137,3 @@ |
2679 | 'ContactListButtonDelegate', |
2680 | objectName='contactListView.importFromSimCardButton') |
2681 | return import_from_sim_button.visible |
2682 | - |
2683 | - def reveal_bottom_edge_page(self): |
2684 | - """Bring the bottom edge page to the screen""" |
2685 | - self.bottomEdgePageOpened.wait_for(False) |
2686 | - try: |
2687 | - action_item = self.wait_select_single(objectName='bottomEdgeDragArea') |
2688 | - action_item.enabled.wait_for(True) |
2689 | - start_x = (action_item.globalRect.x + |
2690 | - (action_item.globalRect.width * 0.5)) |
2691 | - start_y = action_item.globalRect.y + (action_item.height * 0.2) |
2692 | - stop_y = start_y - (self.height * 0.7) |
2693 | - self.pointing_device.drag( |
2694 | - start_x, start_y, start_x, stop_y, rate=2) |
2695 | - #self pointer became invalid at this point |
2696 | - #self.bottomEdgePageOpened.wait_for(True) |
2697 | - except dbus.StateNotFoundError: |
2698 | - logger.error('ButtomEdge element not found.') |
2699 | - raise |
2700 | |
2701 | === modified file 'tests/autopilot/address_book_app/tests/test_add_contact.py' |
2702 | --- tests/autopilot/address_book_app/tests/test_add_contact.py 2015-10-20 03:38:07 +0000 |
2703 | +++ tests/autopilot/address_book_app/tests/test_add_contact.py 2016-01-07 13:19:12 +0000 |
2704 | @@ -36,8 +36,6 @@ |
2705 | contact_editor = self.app.main_window.go_to_add_contact() |
2706 | |
2707 | # Check if the contact list disapear and contact editor appears |
2708 | - #FIXME: list_page became an invalid pointer after push a new page |
2709 | - #self.assertThat(list_page.bottomEdgePageOpened, Eventually(Equals(True))) |
2710 | self.assertThat(contact_editor.visible, Eventually(Equals(True))) |
2711 | self.assertThat(contact_editor.active, Eventually(Equals(True))) |
2712 | |
2713 | @@ -46,7 +44,7 @@ |
2714 | |
2715 | # Check if the contact list is visible again |
2716 | self.assertThat(list_page.visible, Eventually(Equals(True))) |
2717 | - self.assertThat(list_page.bottomEdgePageOpened, Eventually(Equals(False))) |
2718 | + self.app.main_window.wait_bottom_edge(False) |
2719 | |
2720 | # Check if the contact list still empty |
2721 | list_view = self.app.main_window.get_contact_list_view() |
2722 | |
2723 | === modified file 'tests/autopilot/address_book_app/tests/test_create_new_from_uri.py' |
2724 | --- tests/autopilot/address_book_app/tests/test_create_new_from_uri.py 2015-10-20 03:38:07 +0000 |
2725 | +++ tests/autopilot/address_book_app/tests/test_create_new_from_uri.py 2016-01-07 13:19:12 +0000 |
2726 | @@ -23,8 +23,6 @@ |
2727 | |
2728 | def test_save_new_contact(self): |
2729 | list_page = self.app.main_window.get_contact_list_page() |
2730 | - #FIXME: contacts list object became invalid after push a new page |
2731 | - #list_page.bottomEdgePageOpened.wait_for(True) |
2732 | |
2733 | edit_page = self.app.main_window.get_contact_edit_page() |
2734 | self.assertThat(edit_page.visible, Eventually(Equals(True))) |
2735 | |
2736 | === modified file 'tests/autopilot/address_book_app/tests/test_edit_contact.py' |
2737 | --- tests/autopilot/address_book_app/tests/test_edit_contact.py 2015-10-20 03:38:07 +0000 |
2738 | +++ tests/autopilot/address_book_app/tests/test_edit_contact.py 2016-01-07 13:19:12 +0000 |
2739 | @@ -167,16 +167,14 @@ |
2740 | self.clear_text_on_field(last_name_field) |
2741 | |
2742 | # check if is possible to save a contact without name |
2743 | - self.app.main_window.save() |
2744 | - accept_button = self.app.main_window.get_action("save") |
2745 | - self.assertThat(accept_button.enabled, Eventually(Equals(False))) |
2746 | + self.assertThat(edit_page.saveActionEnabled, Eventually(Equals(False))) |
2747 | |
2748 | # Cancel edit |
2749 | self.app.main_window.cancel() |
2750 | |
2751 | # Check if the names still there |
2752 | view_page = self.app.main_window.get_contact_view_page() |
2753 | - self.assertThat(view_page.title, Eventually(Equals("Fulano de Tal"))) |
2754 | + self.assertThat(view_page.headerTitle, Eventually(Equals("Fulano de Tal"))) |
2755 | |
2756 | def test_im_type(self): |
2757 | contact_editor = self.app.main_window.go_to_add_contact() |
2758 | |
2759 | === modified file 'tests/autopilot/address_book_app/tests/test_import_vcard.py' |
2760 | --- tests/autopilot/address_book_app/tests/test_import_vcard.py 2015-11-24 18:18:31 +0000 |
2761 | +++ tests/autopilot/address_book_app/tests/test_import_vcard.py 2016-01-07 13:19:12 +0000 |
2762 | @@ -30,7 +30,7 @@ |
2763 | # check if app enter on import state |
2764 | list_page = self.app.main_window.get_contact_list_page() |
2765 | self.assertThat(list_page.state, Eventually(Equals('vcardImported'))) |
2766 | - self.assertThat(list_page.title, Eventually(Equals('Imported contacts'))) |
2767 | + self.assertThat(list_page.headerTitle, Eventually(Equals('Imported contacts'))) |
2768 | self.assertThat(len(list_page.get_contacts()), Equals(3)) |
2769 | |
2770 | #leave import state and show full contact list |
2771 | |
2772 | === modified file 'tests/autopilot/address_book_app/tests/test_single_pick_mode.py' |
2773 | --- tests/autopilot/address_book_app/tests/test_single_pick_mode.py 2015-04-17 15:22:08 +0000 |
2774 | +++ tests/autopilot/address_book_app/tests/test_single_pick_mode.py 2016-01-07 13:19:12 +0000 |
2775 | @@ -32,6 +32,7 @@ |
2776 | if (contact.visible): |
2777 | item = contact.select_single("QQuickRectangle", |
2778 | objectName="mainItem") |
2779 | + self.assertThat(contact.selected, Eventually(Equals(False))) |
2780 | self.assertThat(item.color, Eventually(Equals(contact.color))) |
2781 | selected_items.append(item) |
2782 | item_to_contacts[item] = contact |
2783 | |
2784 | === modified file 'tests/qml/tst_ContactPreviewPage.qml' |
2785 | --- tests/qml/tst_ContactPreviewPage.qml 2015-11-16 15:44:43 +0000 |
2786 | +++ tests/qml/tst_ContactPreviewPage.qml 2016-01-07 13:19:12 +0000 |
2787 | @@ -104,13 +104,13 @@ |
2788 | function test_preview_contact_with_name() |
2789 | { |
2790 | contactPreviewPage.contact = createContactWithName() |
2791 | - tryCompare(contactPreviewPage, "title", "Fulano") |
2792 | + tryCompare(contactPreviewPage.header, "title", "Fulano") |
2793 | } |
2794 | |
2795 | function test_preview_contact_with_name_and_avatar() |
2796 | { |
2797 | contactPreviewPage.contact = createContactWithNameAndAvatar() |
2798 | - tryCompare(contactPreviewPage, "title", "Fulano") |
2799 | + tryCompare(contactPreviewPage.header, "title", "Fulano") |
2800 | var avatarField = findChild(root, "contactAvatarDetail") |
2801 | tryCompare(avatarField, "avatarUrl", "image://theme/address-book-app") |
2802 | } |
2803 | @@ -120,7 +120,7 @@ |
2804 | compare(vcardParser.contacts.length, 1) |
2805 | var contact = vcardParser.contacts[0] |
2806 | contactPreviewPage.contact = contact |
2807 | - tryCompare(contactPreviewPage, "title", "Forrest Gump") |
2808 | + tryCompare(contactPreviewPage.header, "title", "Forrest Gump") |
2809 | // PhoneNumbers |
2810 | // TEL;TYPE=WORK,VOICE:(111) 555-12121 |
2811 | // TEL;TYPE=HOME,VOICE:(404) 555-1212 |
2812 | @@ -263,8 +263,7 @@ |
2813 | compare(vcardParser.contacts.length, 1) |
2814 | var contact = vcardParser.contacts[0] |
2815 | contactPreviewPage.contact = contact |
2816 | - tryCompare(contactPreviewPage, "title", "Forrest Gump") |
2817 | - |
2818 | + tryCompare(contactPreviewPage.header, "title", "Forrest Gump") |
2819 | |
2820 | // page is enabled by default |
2821 | var avatar = findChild(contactPreviewPage, "avatar") |
FAILED: Continuous integration, rev:547 jenkins. qa.ubuntu. com/job/ address- book-app- ci/1048/ jenkins. qa.ubuntu. com/job/ address- book-app- vivid-i386- ci/351/ console jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- vivid-touch/ 5600/console jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- vivid-armhf/ 5614/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/address- book-app- ci/1048/ rebuild
http://