Merge lp:~renatofilho/address-book-app/new-bottom-edge into lp:address-book-app

Proposed by Renato Araujo Oliveira Filho
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
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.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
548. By Renato Araujo Oliveira Filho

Update BottomEdge editor page with the correct contact model.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
549. By Renato Araujo Oliveira Filho

Removed support for deprecated application arguments.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
566. By Renato Araujo Oliveira Filho

Sync load bottom edge page.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
569. By Renato Araujo Oliveira Filho

Trunk merged.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
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:///usr/share/address-book-app/imports/ABContactListPage.qml:615: TypeError: Cannot read property 'status' of null
file:///usr/share/address-book-app/imports/ABContactListPage.qml:441: TypeError: Cannot read property 'status' of null

- 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:///usr/lib/arm-linux-gnueabihf/qt5/qml/Ubuntu/Components/1.0/Icon.qml:37:5: QML QQuickImage: Failed to get image from provider: image://theme/clear-search

- 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:///usr/lib/arm-linux-gnueabihf/qt5/qml/Ubuntu/Components/1.0/Icon.qml:37:5: QML QQuickImage: Failed to get image from provider: image://theme/clear-search
file:///usr/lib/arm-linux-gnueabihf/qt5/qml/Ubuntu/Components/1.0/Icon.qml:37:5: QML QQuickImage: Failed to get image from provider: image://theme/clear-search
file:///usr/lib/arm-linux-gnueabihf/qt5/qml/Ubuntu/Components/1.0/Icon.qml:37:5: QML QQuickImage: Failed to get image from provider: image://theme/clear-search
file:///usr/lib/arm-linux-gnueabihf/qt5/qml/Ubuntu/Components/1.0/Icon.qml:37:5: QML QQuickImage: Failed to get image from provider: image://theme/clear-search

- pressing edit on a contact is slow again

- I see multiple of these errors everytime trying to edit a contact
file:///usr/lib/arm-linux-gnueabihf/qt5/qml/Ubuntu/Components/1.0/Icon.qml:37:5: QML QQuickImage: Failed to get image from provider: image://theme/clear-search

review: Needs Fixing
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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Renato Araujo Oliveira Filho (renatofilho) wrote :
Download full text (3.2 KiB)

> 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:///usr/share/address-book-app/imports/ABContactListPage.qml:615:
> TypeError: Cannot read property 'status' of null
> file:///usr/share/address-book-app/imports/ABContactListPage.qml:441:
> 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:///usr/lib/arm-linux-
> gnueabihf/qt5/qml/Ubuntu/Components/1.0/Icon.qml:37:5: QML QQuickImage: Failed
> to get image from provider: image://theme/clear-search
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:///usr/lib/arm-linux-
> gnueabihf/qt5/qml/Ubuntu/Components/1.0/Icon.qml:37:5: QML QQuickImage: Failed
> to get image from provider: image://theme/clear-search
> file:///usr/lib/arm-linux-
> gnueabihf/qt5/qml/Ubuntu/Components/1.0/Icon.qml:37:5: QML QQuickImage: Failed
> to get image from provider: image://theme/clear-search
> file:///usr/lib/arm-linux-
> gnueabihf/qt5/qml/Ubuntu/Components/1.0/Icon.qml:37:5: QML QQuickImage: Failed
> to get image from provider: image://theme/clear-search
> file:///usr/lib/arm-linux-
> gnueabihf/qt5/qml/Ubuntu/Components/1.0/Icon.qml:37:5: QML QQuickImage: Failed
> to get image from provider: image://theme/clear-search
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...

Read more...

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
586. By Renato Araujo Oliveira Filho

Fixed field focus while adding new fields on contact editor.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
589. By Renato Araujo Oliveira Filho

Update contact delegate click animation.

590. By Renato Araujo Oliveira Filho

Remove unused variables.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
593. By Renato Araujo Oliveira Filho

set minimum width and height for the app.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
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

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
596. By Renato Araujo Oliveira Filho

Reduce the application width necessary to change into multi column layout.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Bill Filler (bfiller) wrote :

All outstanding issues resolved

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'CMakeLists.txt'
--- CMakeLists.txt 2015-09-03 17:15:32 +0000
+++ CMakeLists.txt 2016-01-07 13:19:12 +0000
@@ -83,6 +83,17 @@
83set(ADDRESS_BOOK_APP_DESKTOP_FILE address-book-app.desktop)83set(ADDRESS_BOOK_APP_DESKTOP_FILE address-book-app.desktop)
84set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall")84set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall")
8585
86#find unity8 qml libraries
87find_path(LIB_UNITY_QML_EXISTS NAMES libUnity-qml.so
88 HINTS "/usr/lib/x86_64-linux-gnu/unity8/qml/Unity/"
89 NO_CMAKE_PATH
90 NO_CMAKE_ENVIRONMENT_PATH
91 NO_SYSTEM_ENVIRONMENT_PATH
92)
93if(!LIB_UNITY_QML_EXISTS)
94 MESSAGE(FATAL_ERROR "unity8 private package not-found")
95endif()
96
86add_subdirectory(data)97add_subdirectory(data)
87add_subdirectory(src)98add_subdirectory(src)
88add_subdirectory(po)99add_subdirectory(po)
89100
=== modified file 'config.h.in'
--- config.h.in 2015-09-29 19:03:44 +0000
+++ config.h.in 2016-01-07 13:19:12 +0000
@@ -10,6 +10,7 @@
10#define QT_EXTRA_IMPORTS_DIR "@QT_EXTRA_IMPORTS_DIR@"10#define QT_EXTRA_IMPORTS_DIR "@QT_EXTRA_IMPORTS_DIR@"
11#define ADDRESS_BOOK_APP_CLICK_PACKAGE "@CLICK_MODE@"11#define ADDRESS_BOOK_APP_CLICK_PACKAGE "@CLICK_MODE@"
12#define I18N_DIRECTORY "@CMAKE_INSTALL_PREFIX@/share/locale"12#define I18N_DIRECTORY "@CMAKE_INSTALL_PREFIX@/share/locale"
13#define UNITY8_QML_PATH "/usr/lib/@CMAKE_C_LIBRARY_ARCHITECTURE@/unity8/qml/"
1314
14#define SETTINGS_ORGANIZATION_NAME "com.ubuntu.address-book"15#define SETTINGS_ORGANIZATION_NAME "com.ubuntu.address-book"
15#define SETTINGS_ORGANIZATION_DOMAIN "canonical.com"16#define SETTINGS_ORGANIZATION_DOMAIN "canonical.com"
1617
=== modified file 'debian/control'
--- debian/control 2015-10-16 13:37:25 +0000
+++ debian/control 2016-01-07 13:19:12 +0000
@@ -52,6 +52,7 @@
52 qtdeclarative5-ubuntu-history0.1,52 qtdeclarative5-ubuntu-history0.1,
53 qtdeclarative5-ubuntu-keyboard-extensions0.1,53 qtdeclarative5-ubuntu-keyboard-extensions0.1,
54 qtdeclarative5-ubuntu-telephony-phonenumber0.1 (>= 0.1+14.10.20140715.1),54 qtdeclarative5-ubuntu-telephony-phonenumber0.1 (>= 0.1+14.10.20140715.1),
55 unity8-private,
55 ${misc:Depends},56 ${misc:Depends},
56 ${shlibs:Depends},57 ${shlibs:Depends},
57Description: Address Book application58Description: Address Book application
5859
=== modified file 'src/app/addressbookapp.cpp'
--- src/app/addressbookapp.cpp 2015-12-18 13:48:47 +0000
+++ src/app/addressbookapp.cpp 2016-01-07 13:19:12 +0000
@@ -44,8 +44,6 @@
44{44{
45 qDebug() << "usage:"45 qDebug() << "usage:"
46 << arguments.at(0).toUtf8().constData()46 << arguments.at(0).toUtf8().constData()
47 << "[addressbook:///addphone?id=<contact-id>&phone=<phone-number>]"
48 << "[addressbook:///addnewphone?phone=<phone-number>]"
49 << "[addressbook:///contact?id=<contact-id>]"47 << "[addressbook:///contact?id=<contact-id>]"
50 << "[addressbook:///create?phone=<phone-number>]"48 << "[addressbook:///create?phone=<phone-number>]"
51 << "[addressbook:///pick?single=<true/false>]"49 << "[addressbook:///pick?single=<true/false>]"
@@ -104,8 +102,7 @@
104 m_netManager(new QNetworkConfigurationManager),102 m_netManager(new QNetworkConfigurationManager),
105 m_pickingMode(false),103 m_pickingMode(false),
106 m_testMode(false),104 m_testMode(false),
107 m_withArgs(false),105 m_withArgs(false)
108 m_withKeyboard(false)
109{106{
110 s_elapsed.start();107 s_elapsed.start();
111 setOrganizationName(SETTINGS_ORGANIZATION_NAME);108 setOrganizationName(SETTINGS_ORGANIZATION_NAME);
@@ -194,10 +191,13 @@
194 this, SLOT(onViewStatusChanged(QQuickView::Status)));191 this, SLOT(onViewStatusChanged(QQuickView::Status)));
195 QObject::connect(m_view->engine(), SIGNAL(quit()), SLOT(quit()));192 QObject::connect(m_view->engine(), SIGNAL(quit()), SLOT(quit()));
196193
194 m_view->setMinimumWidth(300);
195 m_view->setMinimumHeight(500);
197 m_view->setResizeMode(QQuickView::SizeRootObjectToView);196 m_view->setResizeMode(QQuickView::SizeRootObjectToView);
198 m_view->setTitle("AddressBook");197 m_view->setTitle("AddressBook");
199 qDebug() << "New import path:" << QCoreApplication::applicationDirPath() + "/" + importPath("");198 qDebug() << "New import path:" << QCoreApplication::applicationDirPath() + "/" + importPath("");
200 m_view->engine()->addImportPath(QCoreApplication::applicationDirPath() + "/" + importPath(""));199 m_view->engine()->addImportPath(QCoreApplication::applicationDirPath() + "/" + importPath(""));
200 m_view->engine()->addImportPath(UNITY8_QML_PATH);
201 m_view->rootContext()->setContextProperty("QTCONTACTS_MANAGER_OVERRIDE", defaultManager);201 m_view->rootContext()->setContextProperty("QTCONTACTS_MANAGER_OVERRIDE", defaultManager);
202 m_view->rootContext()->setContextProperty("application", this);202 m_view->rootContext()->setContextProperty("application", this);
203 m_view->rootContext()->setContextProperty("contactKey", contactKey);203 m_view->rootContext()->setContextProperty("contactKey", contactKey);
@@ -318,17 +318,12 @@
318318
319 if (methodsMetaData.isEmpty()) {319 if (methodsMetaData.isEmpty()) {
320 QStringList args;320 QStringList args;
321 //edit
322 args << "id" << "phone";
323 methodsMetaData.insert("addphone", args);
324 args.clear();
325
326 //view321 //view
327 args << "id";322 args << "id";
328 methodsMetaData.insert("contact", args);323 methodsMetaData.insert("contact", args);
329 args.clear();324 args.clear();
330325
331 //add326 //create
332 args << "phone";327 args << "phone";
333 methodsMetaData.insert("create", args);328 methodsMetaData.insert("create", args);
334 args.clear();329 args.clear();
@@ -342,11 +337,6 @@
342 args << "url";337 args << "url";
343 methodsMetaData.insert("importvcard", args);338 methodsMetaData.insert("importvcard", args);
344 args.clear();339 args.clear();
345
346 //addnewphone
347 args << "phone";
348 methodsMetaData.insert("addnewphone", args);
349 args.clear();
350 }340 }
351341
352 QUrlQuery query(url);342 QUrlQuery query(url);
@@ -448,26 +438,6 @@
448 qDebug() << "ELAPSED:" << s_elapsed.elapsed() / 1000.0;438 qDebug() << "ELAPSED:" << s_elapsed.elapsed() / 1000.0;
449}439}
450440
451bool AddressBookApp::notify(QObject *obj, QEvent *event)
452{
453 switch(event->type())
454 {
455 case QEvent::KeyPress:
456 // we have no way to detect when a physical keyboard is connected, so we
457 // assume there is one when the down key is pressed
458 if (!m_withKeyboard && (static_cast<QKeyEvent*>(event)->key() == Qt::Key_Down)) {
459 m_withKeyboard = true;
460 Q_EMIT usingKeyboardChanged();
461 return false;
462 }
463 break;
464 default:
465 break;
466 }
467
468 return QGuiApplication::notify(obj, event);
469}
470
471QString AddressBookApp::callbackApplication() const441QString AddressBookApp::callbackApplication() const
472{442{
473 return m_callbackApplication;443 return m_callbackApplication;
@@ -497,7 +467,3 @@
497 return !m_updateWatcher.isNull();467 return !m_updateWatcher.isNull();
498}468}
499469
500bool AddressBookApp::usingKeyboard() const
501{
502 return m_withKeyboard;
503}
504470
=== modified file 'src/app/addressbookapp.h'
--- src/app/addressbookapp.h 2015-12-16 18:35:33 +0000
+++ src/app/addressbookapp.h 2016-01-07 13:19:12 +0000
@@ -32,7 +32,6 @@
32 Q_PROPERTY(bool isOnline READ isOnline NOTIFY isOnlineChanged)32 Q_PROPERTY(bool isOnline READ isOnline NOTIFY isOnlineChanged)
33 Q_PROPERTY(bool serverSafeMode READ serverSafeMode NOTIFY serverSafeModeChanged)33 Q_PROPERTY(bool serverSafeMode READ serverSafeMode NOTIFY serverSafeModeChanged)
34 Q_PROPERTY(bool updating READ updating NOTIFY updatingChanged)34 Q_PROPERTY(bool updating READ updating NOTIFY updatingChanged)
35 Q_PROPERTY(bool usingKeyboard READ usingKeyboard NOTIFY usingKeyboardChanged)
3635
37public:36public:
38 AddressBookApp(int &argc, char **argv);37 AddressBookApp(int &argc, char **argv);
@@ -46,14 +45,12 @@
46 bool isOnline() const;45 bool isOnline() const;
47 bool serverSafeMode() const;46 bool serverSafeMode() const;
48 bool updating() const;47 bool updating() const;
49 bool usingKeyboard() const;
5048
51Q_SIGNALS:49Q_SIGNALS:
52 void callbackApplicationChanged();50 void callbackApplicationChanged();
53 void isOnlineChanged();51 void isOnlineChanged();
54 void serverSafeModeChanged();52 void serverSafeModeChanged();
55 void updatingChanged();53 void updatingChanged();
56 void usingKeyboardChanged();
57 void sourcesChanged();54 void sourcesChanged();
5855
59public Q_SLOTS:56public Q_SLOTS:
@@ -69,8 +66,6 @@
69 // debug66 // debug
70 void elapsed() const;67 void elapsed() const;
7168
72protected:
73 bool notify(QObject *obj, QEvent *event);
7469
75private Q_SLOTS:70private Q_SLOTS:
76 void onUpdateCallFinished(QDBusPendingCallWatcher *watcher);71 void onUpdateCallFinished(QDBusPendingCallWatcher *watcher);
@@ -90,7 +85,6 @@
90 bool m_pickingMode;85 bool m_pickingMode;
91 bool m_testMode;86 bool m_testMode;
92 bool m_withArgs;87 bool m_withArgs;
93 bool m_withKeyboard;
94};88};
9589
96#endif90#endif
9791
=== modified file 'src/imports/ABContactEditorPage.qml'
--- src/imports/ABContactEditorPage.qml 2015-12-16 18:35:33 +0000
+++ src/imports/ABContactEditorPage.qml 2016-01-07 13:19:12 +0000
@@ -26,31 +26,33 @@
26 objectName: "contactEditorPage"26 objectName: "contactEditorPage"
2727
28 property alias backIconName: backAction.iconName28 property alias backIconName: backAction.iconName
29
30 // Property used on unit tests29 // Property used on unit tests
31 readonly property alias saveActionEnabled: saveAction.enabled30 readonly property alias saveActionEnabled: saveAction.enabled
3231
33 head.backAction: Action {32 leadingActions: [
34 id: backAction33 Action {
3534 id: backAction
36 objectName: "cancel"35
37 name: "cancel"36 objectName: "cancel"
3837 name: "cancel"
39 text: i18n.tr("Cancel")38 text: i18n.tr("Cancel")
40 iconName: "back"39 iconName: "down"
41 // WORKAROUND: SDK does not unregister shortcut on object destruction40 enabled: root.active && root.enabled
42 // we need to do it manually. (bug #1518420)41 shortcut: "Esc"
43 enabled: root.active && root.enabled42 onTriggered: {
44 shortcut: enabled ? "Esc" : undefined43 root.cancel()
45 onTriggered: root.cancel()44 if (root.pageStack.contactListPage)
46 }45 root.pageStack.contactListPage.forceActiveFocus()
4746 }
48 head.actions: [47 }
48 ]
49
50 headerActions: [
49 Action {51 Action {
50 id: saveAction52 id: saveAction
53
51 objectName: "save"54 objectName: "save"
52 name: "save"55 name: "save"
53
54 text: i18n.tr("Save")56 text: i18n.tr("Save")
55 iconName: "ok"57 iconName: "ok"
56 enabled: root.isContactValid && root.active && root.enabled58 enabled: root.isContactValid && root.active && root.enabled
@@ -62,6 +64,7 @@
62 onContactSaved: {64 onContactSaved: {
63 if (pageStack.contactListPage) {65 if (pageStack.contactListPage) {
64 pageStack.contactListPage.moveListToContact(contact)66 pageStack.contactListPage.moveListToContact(contact)
67 pageStack.contactListPage.forceActiveFocus()
65 }68 }
66 }69 }
67}70}
6871
=== modified file 'src/imports/ABContactListPage.qml'
--- src/imports/ABContactListPage.qml 2015-12-14 18:29:23 +0000
+++ src/imports/ABContactListPage.qml 2016-01-07 13:19:12 +0000
@@ -1,4 +1,4 @@
1/*1/*
2 * Copyright (C) 2012-2015 Canonical, Ltd.2 * Copyright (C) 2012-2015 Canonical, Ltd.
3 *3 *
4 * This program is free software; you can redistribute it and/or modify4 * This program is free software; you can redistribute it and/or modify
@@ -26,71 +26,73 @@
26import Ubuntu.AddressBook.Base 0.126import Ubuntu.AddressBook.Base 0.1
27import Ubuntu.AddressBook.ContactShare 0.127import Ubuntu.AddressBook.ContactShare 0.1
2828
29import "." as AB
3029
31Page {30Page {
32 id: mainPage31 id: mainPage
33 objectName: "contactListPage"32 objectName: "contactListPage"
3433
34 property var viewPage: null
35 property bool pickMode: false35 property bool pickMode: false
36 property alias contentHubTransfer: contactExporter.activeTransfer36 property alias contentHubTransfer: contactExporter.activeTransfer
37 property bool pickMultipleContacts: false37 property bool pickMultipleContacts: false
38 property QtObject contactIndex: null38 property QtObject contactIndex: null
39 property string newPhoneToAdd: ""
40 property alias contactManager: contactList.manager39 property alias contactManager: contactList.manager
41 property alias contactViewPage: contactViewPageConnections.target40
42 property alias contactEditorPage: contactEditorPageConnections.target
43 property var _busyDialog: null41 property var _busyDialog: null
44 property bool _importingTestData: false42 property bool _importingTestData: false
45 property bool _creatingContact: false43 property bool _creatingContact: false
4644
47 readonly property bool bottomEdgePageOpened: bottomEdge.opened && bottomEdge.fullLoaded45 readonly property string currentViewContactId: viewPage && viewPage.contact ? viewPage.contact.contactId : ""
48 readonly property bool isEmpty: (contactList.count === 0)46 readonly property bool isEmpty: (contactList.count === 0)
49 readonly property bool allowToQuit: (application.callbackApplication.length > 0)47 readonly property bool allowToQuit: (application.callbackApplication.length > 0)
50 readonly property var contactModel: contactList.listModel ? contactList.listModel : null48 readonly property var contactModel: contactList.listModel ? contactList.listModel : null
51 readonly property bool searching: (state === "searching" || state === "newphoneSearching")49 readonly property bool searching: state === "searching"
50 readonly property string headerTitle: pageHeader.title
5251
53 // this function is used to reset the contact list page to the default state if it was called52 // this function is used to reset the contact list page to the default state if it was called
54 // from the uri. For example when called to add a new contact53 // from the uri. For example when called to add a new contact
55 function returnToNormalState()54 function returnToNormalState()
56 {55 {
57 // these two states are the only state that need to be reset
58 if (state == "newphoneSearching" || state == "newphone") {
59 state = "default"
60 }
61 application.callbackApplication = ""56 application.callbackApplication = ""
62 }57 }
6358
64 function createContactWithPhoneNumber(phoneNumber)59 function createContactWithPhoneNumber(phoneNumber)
65 {60 {
66 var newContact = ContactsJS.createEmptyContact(phoneNumber, mainPage);61 var newContact = ContactsJS.createEmptyContact(phoneNumber, mainPage);
67 openEditPage({model: contactList.listModel,62 if (bottomEdgeLoader.status == Loader.Ready) {
68 contact: newContact,63 bottomEdgeLoader.editContact(newContact)
69 initialFocusSection: "name"},64 } else {
70 mainPage);65 contactList.currentIndex = -1
71 }66 var incubator = pageStack.addPageToNextColumn(mainPage,
7267 Qt.resolvedUrl("ABContactEditorPage.qml"),
73 function openEditPage(editPageProperties, sourcePage) {68 { model: mainPage.contactModel,
74 var component = Qt.createComponent(Qt.resolvedUrl("ABContactEditorPage.qml"))69 contact: newContact,
75 if (component.status === Component.Ready) {70 backIconName: 'back',
76 mainPage.contactEditorPage = component.createObject(mainPage, editPageProperties)71 enabled: false
77 pageStack.addPageToNextColumn(sourcePage, mainPage.contactEditorPage)72 })
78 }73 }
79 }74 }
8075
81 function openViewPage(viewPageProperties) {76 function openViewPage(viewPageProperties) {
82 var component = Qt.createComponent(Qt.resolvedUrl("ABContactViewPage.qml"))77 var component = Qt.createComponent(Qt.resolvedUrl("ABContactViewPage.qml"))
83 if (component.status === Component.Ready) {78 var incubator = pageStack.addPageToNextColumn(mainPage, component, viewPageProperties)
84 mainPage.contactViewPage = component.createObject(mainPage, viewPageProperties)79 if (incubator && (incubator.status === Component.Loading)) {
85 pageStack.addPageToNextColumn(mainPage, mainPage.contactViewPage)80 incubator.onStatusChanged = function(status) {
81 if (status === Component.Ready)
82 mainPage.viewPage = incubator.object
83 }
84 } else if (incubator && incubator.status ===- Component.Ready) {
85 mainPage.viewPage = incubator.object
86 } else {
87 mainPage.viewPage = null
86 }88 }
87 }89 }
8890
89 function showContact(contact)91 function showContact(contact)
90 {92 {
91 var currentContact = contactList.listModel.contacts[contactList.currentIndex]93 var currentContact = contactList.listModel.contacts[contactList.currentIndex]
92 if (currentContact && contactViewPage && contactViewPage.contact && (contactViewPage.contact.contactId === currentContact.contactId)) {94 if (currentContact && (mainPage.currentViewContactId === currentContact.contactId)) {
93 console.debug("Skip show contact")95 // contact view already opened with this contact
94 return96 return
95 }97 }
9698
@@ -109,13 +111,6 @@
109 contactId: contactId});111 contactId: contactId});
110 }112 }
111113
112 function addPhoneToContact(contactId, phoneNumber)
113 {
114 openViewPage({model: contactList.listModel,
115 contactId: contactId,
116 addPhoneToContact: phoneNumber});
117 }
118
119 function importContact(urls)114 function importContact(urls)
120 {115 {
121 mainPage._busyDialog = PopupUtils.open(busyDialogComponent, mainPage)116 mainPage._busyDialog = PopupUtils.open(busyDialogComponent, mainPage)
@@ -157,20 +152,6 @@
157 }152 }
158 }153 }
159154
160 function addNewPhone(phoneNumber)
161 {
162 newPhoneToAdd = phoneNumber
163 state = "newphone"
164 contactList.reset()
165 }
166
167 function showContactEditorPage(editorPage) {
168 contactList.currentIndex = -1;
169 mainPage.contactEditorPage = editorPage;
170 pageStack.addPageToNextColumn(mainPage, editorPage);
171 editorPage.contactSaved.connect(onNewContactSaved);
172 editorPage.enabled = true
173 }
174155
175 function onNewContactSaved(contact) {156 function onNewContactSaved(contact) {
176 _creatingContact = true157 _creatingContact = true
@@ -190,13 +171,57 @@
190 {171 {
191 if ((contactList.currentIndex >= 0) && (pageStack.columns > 1)) {172 if ((contactList.currentIndex >= 0) && (pageStack.columns > 1)) {
192 var currentContact = contactList.listModel.contacts[contactList.currentIndex]173 var currentContact = contactList.listModel.contacts[contactList.currentIndex]
193 if (contactViewPage && contactViewPage.contact && (contactViewPage.contact.contactId === currentContact.contactId))174 if (!currentContact) {
175 var component = Qt.createComponent(Qt.resolvedUrl("ABMultiColumnEmptyState.qml"))
176 var searching = contactList.filterTerm !== ""
177 pageStack.addPageToNextColumn(mainPage, component,
178 { headerTitle: searching ? i18n.tr("No contact found") : i18n.tr("No contacts") })
179 return
180 }
181 if (currentContact && (mainPage.currentViewContactId === currentContact.contactId))
194 return182 return
195183
196 contactList.view._fetchContact(contactList.currentIndex, currentContact)184 contactList.view._fetchContact(contactList.currentIndex, currentContact)
197 }185 }
198 }186 }
199187
188 header: PageHeader {
189 id: pageHeader
190
191 property alias leadingActions: leadingBar.actions
192 property alias trailingActions: trailingBar.actions
193 property alias sectionsModel: sections.model
194
195 title: i18n.tr("Contacts")
196 //flickable: contactList.view
197 trailingActionBar {
198 id: trailingBar
199 }
200 leadingActionBar {
201 id: leadingBar
202 }
203 extension: Sections {
204 id: sections
205 anchors {
206 left: parent.left
207 leftMargin: units.gu(2)
208 bottom: parent.bottom
209 }
210 onSelectedIndexChanged: {
211 switch (selectedIndex) {
212 case 0:
213 contactList.showAllContacts()
214 break;
215 case 1:
216 contactList.showFavoritesContacts()
217 break;
218 default:
219 break;
220 }
221 }
222 }
223 }
224
200 // This timer is to avoid fetch unecessary contact if the user select the contacts too fast225 // This timer is to avoid fetch unecessary contact if the user select the contacts too fast
201 // while navigating on contact list with keyboard226 // while navigating on contact list with keyboard
202 Timer {227 Timer {
@@ -215,23 +240,23 @@
215 objectName: "contactListView"240 objectName: "contactListView"
216241
217 focus: true242 focus: true
218 showImportOptions: !mainPage.pickMode &&243 showImportOptions: !mainPage.pickMode &&
219 mainPage.newPhoneToAdd === "" &&244 pageStack.bottomEdge &&
220 (!mainPage.contactEditorPage || !mainPage.contactEditorPage.active)245 (pageStack.bottomEdge.status === BottomEdge.Hidden)
221 anchors {246 anchors {
222 top: parent.top247 top: parent.top
248 topMargin: pageHeader.height
223 left: parent.left249 left: parent.left
224 bottom: keyboard.top250 bottom: keyboard.top
225 right: parent.right251 right: parent.right
226 }252 }
227 currentIndex: 0253 currentIndex: -1
228 filterTerm: searchField.text254 filterTerm: searchField.text
229 multiSelectionEnabled: true255 multiSelectionEnabled: true
230 multipleSelection: (mainPage.pickMode && mainPage.pickMultipleContacts) || !mainPage.pickMode256 multipleSelection: (mainPage.pickMode && mainPage.pickMultipleContacts) || !mainPage.pickMode
231 highlightSelected: application.usingKeyboard && !mainPage._creatingContact257 showNewContact: (pageStack.columns > 1) && pageStack.bottomEdge && (pageStack.bottomEdge.status === BottomEdge.Committed)
258 highlightSelected: pageStack.hasKeyboard && !mainPage._creatingContact
232 onAddContactClicked: mainPage.createContactWithPhoneNumber(label)259 onAddContactClicked: mainPage.createContactWithPhoneNumber(label)
233 onAddNewContactClicked: mainPage.createContactWithPhoneNumber(mainPage.newPhoneToAdd)
234
235 onContactClicked: mainPage.showContact(contact)260 onContactClicked: mainPage.showContact(contact)
236 onIsInSelectionModeChanged: mainPage.state = isInSelectionMode ? "selection" : "default"261 onIsInSelectionModeChanged: mainPage.state = isInSelectionMode ? "selection" : "default"
237 onSelectionCanceled: {262 onSelectionCanceled: {
@@ -252,14 +277,17 @@
252 contactList.currentIndex = 0277 contactList.currentIndex = 0
253 }278 }
254 }279 }
280
255 onCountChanged: {281 onCountChanged: {
256 if (mainPage.active &&282 if (mainPage.active &&
257 (pageStack.columns > 1) &&283 (pageStack.columns > 1) &&
258 (contactList.currentIndex === -1)) {284 (contactList.currentIndex === -1) &&
285 (pageStack.bottomEdge.status === BottomEdge.Hidden)) {
259 contactList.currentIndex = 0286 contactList.currentIndex = 0
260 }287 }
261 mainPage.delayFetchContact()288 mainPage.delayFetchContact()
262 }289 }
290
263 onCurrentIndexChanged: {291 onCurrentIndexChanged: {
264 if (!mainPage.contactIndex)292 if (!mainPage.contactIndex)
265 mainPage.delayFetchContact()293 mainPage.delayFetchContact()
@@ -267,7 +295,7 @@
267295
268 Keys.onReturnPressed: {296 Keys.onReturnPressed: {
269 var currentContact = contactList.listModel.contacts[contactList.currentIndex]297 var currentContact = contactList.listModel.contacts[contactList.currentIndex]
270 if (contactViewPage && contactViewPage.contact && (contactViewPage.contact.contactId === currentContact.contactId))298 if (mainPage.currentViewContactId === currentContact.contactId)
271 return299 return
272300
273 contactList.view._fetchContact(contactList.currentIndex, currentContact)301 contactList.view._fetchContact(contactList.currentIndex, currentContact)
@@ -277,7 +305,7 @@
277 //because of that we need this305 //because of that we need this
278 Keys.onRightPressed: {306 Keys.onRightPressed: {
279 // only move focus away when in edit mode307 // only move focus away when in edit mode
280 if (mainPage.contactEditorPage) {308 if (pageStack.bottomEdge.status === BottomEdge.Committed) {
281 var next = pageStack._nextItemInFocusChain(view, true)309 var next = pageStack._nextItemInFocusChain(view, true)
282 if (next === searchField) {310 if (next === searchField) {
283 pageStack._nextItemInFocusChain(next, true)311 pageStack._nextItemInFocusChain(next, true)
@@ -292,8 +320,6 @@
292 }320 }
293 }321 }
294322
295
296
297 TextField {323 TextField {
298 id: searchField324 id: searchField
299325
@@ -302,58 +328,57 @@
302 readonly property bool _allowFocus: true328 readonly property bool _allowFocus: true
303329
304 anchors {330 anchors {
331 top: parent ? parent.top : undefined
305 left: parent ? parent.left : undefined332 left: parent ? parent.left : undefined
306 right: parent ? parent.right : undefined333 right: parent ? parent.right : undefined
334 margins: units.gu(1)
307 rightMargin: units.gu(2)335 rightMargin: units.gu(2)
308 }336 }
309337
310 visible: false338 visible: false
311 inputMethodHints: Qt.ImhNoPredictiveText339 inputMethodHints: Qt.ImhNoPredictiveText
312 placeholderText: i18n.tr("Search...")340 placeholderText: i18n.tr("Search...")
341 onVisibleChanged: {
342 if (visible) {
343 if (activeFocus) {
344 Qt.inputMethod.show()
345 } else {
346 searchField.forceActiveFocus()
347 }
348 }
349 }
350
313 Keys.onTabPressed: contactList.forceActiveFocus()351 Keys.onTabPressed: contactList.forceActiveFocus()
314 Keys.onDownPressed: contactList.forceActiveFocus()352 Keys.onDownPressed: contactList.forceActiveFocus()
315 }353 }
316354
317 Connections {
318 target: mainPage.head.sections
319 onSelectedIndexChanged: {
320 switch (mainPage.head.sections.selectedIndex) {
321 case 0:
322 contactList.showAllContacts()
323 break;
324 case 1:
325 contactList.showFavoritesContacts()
326 break;
327 default:
328 break;
329 }
330 }
331 }
332
333 state: "default"355 state: "default"
334 states: [356 states: [
335 PageHeadState {357 State {
336 id: defaultState358 id: defaultState
337
338 name: "default"359 name: "default"
339 backAction: Action {360
340 visible: mainPage.allowToQuit361 property list<QtObject> leadingActions: [
341 iconName: "back"362 Action {
342 text: i18n.tr("Quit")363 visible: mainPage.allowToQuit
343 onTriggered: {364 iconName: "back"
344 application.goBackToSourceApp()365 text: i18n.tr("Quit")
345 mainPage.returnToNormalState()366 onTriggered: {
367 application.goBackToSourceApp()
368 mainPage.returnToNormalState()
369 }
346 }370 }
347 }371 ]
348 actions: [372
373 property list<QtObject> trailingActions: [
349 Action {374 Action {
350 text: i18n.tr("Search")375 text: i18n.tr("Search")
351 iconName: "search"376 iconName: "search"
352 visible: !mainPage.isEmpty377 visible: !mainPage.isEmpty
353 enabled: mainPage.state === "default"378 enabled: visible && (mainPage.state === "default")
354 shortcut: "Ctrl+F"379 shortcut: "Ctrl+F"
355 onTriggered: {380 onTriggered: {
356 mainPage.state = (mainPage.state === "newphone" ? "newphoneSearching" : "searching")381 mainPage.state = "searching"
357 contactList.showAllContacts()382 contactList.showAllContacts()
358 searchField.forceActiveFocus()383 searchField.forceActiveFocus()
359 }384 }
@@ -391,73 +416,85 @@
391 }416 }
392 }417 }
393 ]418 ]
419
394 PropertyChanges {420 PropertyChanges {
395 target: mainPage.head421 target: pageHeader
396 backAction: defaultState.backAction422
397 actions: defaultState.actions
398 // TRANSLATORS: this refers to all contacts423 // TRANSLATORS: this refers to all contacts
399 sections.model: [i18n.tr("All"), i18n.tr("Favorites")]424 sectionsModel: [i18n.tr("All"), i18n.tr("Favorites")]
425 leadingActions: defaultState.leadingActions
426 trailingActions: defaultState.trailingActions
400 }427 }
401 PropertyChanges {428 PropertyChanges {
402 target: searchField429 target: searchField
403 text: ""430 text: ""
404 }431 }
405 PropertyChanges {432 PropertyChanges {
406 target: bottomEdge433 target: bottomEdgeLoader
407 enabled: true434 enabled: true
408 }435 }
409 },436 },
410 PageHeadState {437 State {
411 id: searchingState438 id: searchingState
412
413 name: "searching"439 name: "searching"
414 backAction: Action {440
415 iconName: "back"441 property list<QtObject> leadingActions: [
416 text: i18n.tr("Cancel")442 Action {
417 enabled: mainPage.state === "searching" && !mainPage.contactEditorPage && mainPage.active443 iconName: "back"
418 shortcut: "Esc"444 text: i18n.tr("Cancel")
419 onTriggered: {445 enabled: (mainPage.state === "searching") &&
420 mainPage.head.sections.selectedIndex = 0446 mainPage.active &&
421 mainPage.state = (mainPage.state === "newphoneSearching" ? "newphone" : "default")447 (!pageStack.bottomEdge ||
422 contactList.forceActiveFocus()448 (pageStack.bottomEdge && (pageStack.bottomEdge.status === BottomEdge.Hidden))) &&
449 ((pageStack.columns === 1) ||
450 (mainPage.viewPage && mainPage.viewPage.active))
451 shortcut:"Esc"
452 onTriggered: {
453 mainPage.head.sections.selectedIndex = 0
454 mainPage.state = "default"
455 contactList.forceActiveFocus()
456 }
423 }457 }
424 }458 ]
425459
426 PropertyChanges {460 PropertyChanges {
427 target: bottomEdge461 target: pageHeader
428 enabled: false462
429 }
430
431 PropertyChanges {
432 target: mainPage.head
433 backAction: searchingState.backAction
434 contents: searchField463 contents: searchField
464 leadingActions: searchingState.leadingActions
465
435 }466 }
436467
437 PropertyChanges {468 PropertyChanges {
438 target: searchField469 target: bottomEdgeLoader
439 text: ""470 enabled: false
440 }471 }
441472
442 PropertyChanges {473 PropertyChanges {
443 target: searchField474 target: searchField
444 visible: true475 visible: true
445 focus: true476 focus: true
477 text: ""
446 }478 }
447 },479 },
448 PageHeadState {480 State {
449 id: selectionState481 id: selectionState
450
451 name: "selection"482 name: "selection"
452 backAction: Action {483
453 text: i18n.tr("Cancel selection")484 property list<QtObject> leadingActions: [
454 iconName: "back"
455 enabled: mainPage.state === "selection"
456 shortcut: "Esc"
457 onTriggered: contactList.cancelSelection()
458 }
459 actions: [
460 Action {485 Action {
486 objectName: "cancel"
487 name: "cancel"
488 text: i18n.tr("Cancel selection")
489 iconName: "back"
490 enabled: mainPage.state === "selection"
491 onTriggered: contactList.cancelSelection()
492 shortcut: "Esc"
493 }
494 ]
495
496 property list<QtObject> trailingActions: [
497 Action {
461 text: (contactList.selectedItems.count === contactList.count) ? i18n.tr("Unselect All") : i18n.tr("Select All")498 text: (contactList.selectedItems.count === contactList.count) ? i18n.tr("Unselect All") : i18n.tr("Select All")
462 iconName: "select"499 iconName: "select"
463 onTriggered: {500 onTriggered: {
@@ -506,76 +543,48 @@
506 }543 }
507 }544 }
508 ]545 ]
509 PropertyChanges {546
510 target: mainPage.head547 PropertyChanges {
511 backAction: selectionState.backAction548 target: pageHeader
512 actions: selectionState.actions549
513 }550 leadingActions: selectionState.leadingActions
514 PropertyChanges {551 trailingActions: selectionState.trailingActions
515 target: bottomEdge552 }
516 enabled: false553
517 }554 PropertyChanges {
518 },555 target: bottomEdgeLoader
519 PageHeadState {556 enabled: false
520 name: "newphone"557 }
521 extend: "default"558 },
522 head: mainPage.head559 State {
523 PropertyChanges {
524 target: contactList
525 showAddNewButton: true
526 }
527 PropertyChanges {
528 target: mainPage
529 title: i18n.tr("Add contact")
530 }
531 PropertyChanges {
532 target: bottomEdge
533 enabled: false
534 }
535 PropertyChanges {
536 target: contactList
537 detailToPick: -1
538 }
539 },
540 PageHeadState {
541 name: "newphoneSearching"
542 extend: "searching"
543 head: mainPage.head
544 PropertyChanges {
545 target: contactList
546 detailToPick: -1
547 showAddNewButton: true
548 }
549 PropertyChanges {
550 target: bottomEdge
551 enabled: false
552 }
553 },
554 PageHeadState {
555 id: vcardImportedState560 id: vcardImportedState
556
557 name: "vcardImported"561 name: "vcardImported"
558 backAction: Action {562
559 iconName: "back"563 property list<QtObject> leadingActions: [
560 text: i18n.tr("Back")564 Action {
561 onTriggered: {565 objectName: "cancel"
562 contactList.forceActiveFocus()566 name: "cancel"
563 mainPage.state = "default"567 iconName: "back"
564 importedIdsFilter.ids = []568 text: i18n.tr("Back")
569 onTriggered: {
570 contactList.forceActiveFocus()
571 mainPage.state = "default"
572 importedIdsFilter.ids = []
573 }
565 }574 }
566 }575 ]
567 PropertyChanges {576
568 target: mainPage.head577 PropertyChanges {
569 backAction: vcardImportedState.backAction578 target: pageHeader
570 }579
571 PropertyChanges {580 leadingActions: vcardImportedState.leadingActions
572 target: bottomEdge
573 enabled: false
574 }
575 PropertyChanges {
576 target: mainPage
577 title: i18n.tr("Imported contacts")581 title: i18n.tr("Imported contacts")
578 }582 }
583
584 PropertyChanges {
585 target: bottomEdgeLoader
586 enabled: false
587 }
579 }588 }
580 ]589 ]
581590
@@ -614,54 +623,30 @@
614623
615 KeyboardRectangle {624 KeyboardRectangle {
616 id: keyboard625 id: keyboard
626 active: mainPage.active &&
627 (pageStack.bottomEdge && (pageStack.bottomEdge.status === BottomEdge.Hidden))
617 }628 }
618629
619 Column {630 ABEmptyState {
620 id: emptyStateScreen631 id: emptyStateScreen
621632
622 anchors.centerIn: parent633 anchors {
634 verticalCenter: parent.verticalCenter
635 left: parent.left
636 right: parent.right
637 leftMargin: units.gu(6)
638 rightMargin: units.gu(6)
639 }
640
623 height: childrenRect.height641 height: childrenRect.height
624 width: childrenRect.width642 visible: ((pageStack.columns === 1) &&
625 spacing: units.gu(2)643 !contactList.busy &&
626 visible: (!contactList.busy &&
627 !contactList.favouritesIsSelected &&644 !contactList.favouritesIsSelected &&
628 mainPage.isEmpty &&645 mainPage.isEmpty &&
629 (mainPage.newPhoneToAdd === "") &&646 !(contactList.filterTerm && contactList.filterTerm !== ""))
630 !(contactList.filterTerm && contactList.filterTerm !== "")) &&647 text: mainPage.pickMode ?
631 bottomEdge.visible648 i18n.tr("You have no contacts.") :
632649 i18n.tr("Create a new contact by swiping up from the bottom of the screen.")
633 Behavior on visible {
634 SequentialAnimation {
635 PauseAnimation {
636 duration: !emptyStateScreen.visible ? 500 : 0
637 }
638 PropertyAction {
639 target: emptyStateScreen
640 property: "visible"
641 }
642 }
643 }
644
645 Icon {
646 id: emptyStateIcon
647 anchors.horizontalCenter: emptyStateLabel.horizontalCenter
648 height: units.gu(5)
649 width: units.gu(5)
650 opacity: 0.3
651 name: "contact"
652 }
653 Label {
654 id: emptyStateLabel
655 width: mainPage.width - units.gu(12)
656 height: paintedHeight
657 text: mainPage.pickMode ?
658 i18n.tr("You have no contacts.") :
659 i18n.tr("Create a new contact by swiping up from the bottom of the screen.")
660 color: "#5d5d5d"
661 fontSize: "x-large"
662 wrapMode: Text.WordWrap
663 horizontalAlignment: Text.AlignHCenter
664 }
665 }650 }
666651
667 ContactExporter {652 ContactExporter {
@@ -753,103 +738,26 @@
753 }738 }
754 }739 }
755740
756 Component {741 Loader {
757 id: editorPageBottomEdge742 id: bottomEdgeLoader
758 ABContactEditorPage {743
759 backIconName: "down"744 enabled: false
760 implicitWidth: mainPage.width745 active: (pageStack.columns === 1) && bottomEdgeLoader.enabled
761 implicitHeight: mainPage.height746 asynchronous: true
762 model: contactList.listModel747 sourceComponent: ABNewContactBottomEdge {
763 contact: ContactsJS.createEmptyContact("", mainPage)748 parent: mainPage
764 initialFocusSection: "name"749 modelToEdit: mainPage.contactModel
765 enabled: false750 hint.flickable: contactList.view
766 }751 pageStack: mainPage.pageStack
767 }752 enabled: mainPage.active
768753 }
769 Component {754 }
770 id: emptyContact755
771 ContactsUI.ContactDelegate {756 Binding {
772 property Contact contact: Contact {757 target: pageStack
773 Name {758 property: 'bottomEdge'
774 firstName: i18n.tr("New contact")759 value: bottomEdgeLoader.item
775 }760 when: bottomEdgeLoader.status == Loader.Ready
776 Avatar {
777 imageUrl: "image://theme/contact"
778 }
779 }
780 width: mainPage.width
781 }
782 }
783
784 AB.BottomEdge {
785 id: bottomEdge
786 objectName: "bottomEdge"
787
788 property var incubator
789
790 // FIXME: this is a workaround for the lack of fully asynchronous loading
791 // of Pages in AdaptativePageLayout
792 function createObjectAsynchronously(url, properties, callback) {
793 var component = Qt.createComponent(url, Component.Asynchronous);
794 if (component.status == Component.Ready) {
795 incubateObject(component, properties, callback);
796 } else {
797 component.onStatusChanged.connect(function(status) {
798 if (status == Component.Ready) {
799 incubateObject(component, properties, callback);
800 }
801 });
802 }
803 }
804
805 function incubateObject(component, properties, callback) {
806 if (component.status == Component.Ready) {
807 incubator = component.incubateObject(null,
808 properties,
809 Qt.Asynchronous);
810 incubator.onStatusChanged = function(status) {
811 if (status == Component.Ready) {
812 callback(incubator.object);
813 incubator = null;
814 }
815 }
816 }
817 }
818
819 function loadEditorPage() {
820 var newContact = ContactsJS.createEmptyContact("", mainPage);
821 createObjectAsynchronously(Qt.resolvedUrl("ABContactEditorPage.qml"),
822 {model: contactList.listModel,
823 enabled: false,
824 contact: newContact,
825 initialFocusSection: "name"},
826 showContactEditorPage);
827 }
828
829 anchors.fill: parent
830 contentComponent: pageStack.columns === 1 ? editorPageBottomEdge : emptyContact
831 flickable: contactList
832 iconName: "contact-new"
833 backGroundEffectEnabled: pageStack.columns === 1
834
835 onBottomEdgeLoaded: contactList.forceActiveFocus()
836 onOpenBegin: {
837 contactList.prepareNewContact = true;
838 contactList.positionViewAtBeginning();
839 if (pageStack.columns > 1) {
840 loadEditorPage();
841 }
842 }
843 onOpenEnd: {
844 contactList.showNewContact = true;
845 if (pageStack.columns <= 1) {
846 showContactEditorPage(bottomEdge.content);
847 }
848 }
849
850 onClicked: {
851 bottomEdge.open();
852 }
853 }761 }
854762
855 Connections {763 Connections {
@@ -861,6 +769,7 @@
861 mainPage.contactIndex = null769 mainPage.contactIndex = null
862 // at this point the operation has finished already770 // at this point the operation has finished already
863 mainPage._creatingContact = false771 mainPage._creatingContact = false
772 fetchNewContactTimer.restart()
864 }773 }
865 }774 }
866 onImportCompleted: {775 onImportCompleted: {
@@ -890,34 +799,20 @@
890 }799 }
891800
892 Connections {801 Connections {
893 id: contactViewPageConnections802 target: pageStack.bottomEdge
894803 onCommitCompleted: {
895 ignoreUnknownSignals: true804 if (mainPage.state !== "default") {
896 onEditContact: openEditPage(editPageProperties, mainPage.contactViewPage);805 mainPage.head.sections.selectedIndex = 0
897 onActiveChanged: {806 mainPage.state = "default"
898 if (mainPage.contactViewPage &&
899 !mainPage.contactViewPage.active &&
900 (mainPage.contactEditorPage == null)) { // not editing
901 mainPage.contactViewPage = null
902 }807 }
903 }808 }
904 }809 onCollapseCompleted: {
905810 if (!mainPage._creatingContact) {
906 Connections {811 if (contactList.currentIndex === -1)
907 id: contactEditorPageConnections812 contactList.currentIndex = 0
908813 mainPage.delayFetchContact()
909 ignoreUnknownSignals: true
910 onActiveChanged: {
911 if (mainPage.contactEditorPage && !mainPage.contactEditorPage.active) {
912 contactList.prepareNewContact = false;
913 contactList.showNewContact = false;
914 bottomEdge.close();
915 mainPage.contactEditorPage = null
916 contactList.forceActiveFocus()
917 bottomEdge.enabled = true
918 } else if (mainPage.contactEditorPage && !mainPage.contactEditorPage.active) {
919 bottomEdge.enabled = false
920 }814 }
815 contactList.forceActiveFocus()
921 }816 }
922 }817 }
923}818}
924819
=== modified file 'src/imports/ABContactViewPage.qml'
--- src/imports/ABContactViewPage.qml 2015-12-14 18:29:23 +0000
+++ src/imports/ABContactViewPage.qml 2016-01-07 13:19:12 +0000
@@ -1,4 +1,4 @@
1/*1/*
2 * Copyright (C) 2012-2015 Canonical, Ltd.2 * Copyright (C) 2012-2015 Canonical, Ltd.
3 *3 *
4 * This program is free software; you can redistribute it and/or modify4 * This program is free software; you can redistribute it and/or modify
@@ -27,10 +27,35 @@
27 id: root27 id: root
28 objectName: "contactViewPage"28 objectName: "contactViewPage"
2929
30 property string addPhoneToContact: ""30 property bool editing: false
31 signal editContact(var editPageProperties)31 // used by autopilot test
3232 readonly property string headerTitle: header.title
33 // Override Action buttom to add shortcut to it33
34 function editContact(contact)
35 {
36 if (editing)
37 return
38 editing = true
39 var component = Qt.createComponent(Qt.resolvedUrl("ABContactEditorPage.qml"))
40 var incubator = pageStack.addPageToCurrentColumn(root,
41 component,
42 { model: root.model,
43 contact: contact,
44 backIconName: 'back'})
45 if (incubator && (incubator.status === Component.Loading)) {
46 incubator.onStatusChanged = function(status) {
47 if (status === Component.Ready) {
48 incubator.object.Component.destruction.connect(function() {
49 root.editing = false;
50 });
51 }
52 }
53 } else {
54 editing = false
55 }
56 }
57
58 // Shortcut in case of single column
34 Action {59 Action {
35 id: backAction60 id: backAction
3661
@@ -40,7 +65,8 @@
40 onTriggered: pageStack.removePages(root)65 onTriggered: pageStack.removePages(root)
41 }66 }
4267
43 head.actions: [68
69 headerActions: [
44 Action {70 Action {
45 objectName: "share"71 objectName: "share"
46 name: "share"72 name: "share"
@@ -60,12 +86,9 @@
6086
61 text: i18n.tr("Edit")87 text: i18n.tr("Edit")
62 iconName: "edit"88 iconName: "edit"
63 enabled: root.active89 enabled: root.active && !editing
64 shortcut: "Ctrl+e"90 shortcut: "Ctrl+e"
65 onTriggered: {91 onTriggered: root.editContact(root.contact)
66 editContact({model: root.model,
67 contact: root.contact});
68 }
69 }92 }
70 ]93 ]
7194
@@ -80,23 +103,6 @@
80 height: implicitHeight103 height: implicitHeight
81 }104 }
82105
83 // This will load the contact information when the app was launched with
84 // the URI: addressbook:///contact?id=<id>
85 onContactFetched: {
86 if (root.addPhoneToContact != "") {
87 var detailSourceTemplate = "import QtContacts 5.0; PhoneNumber{ number: \"" + root.addPhoneToContact.trim() + "\" }"
88 var newDetail = Qt.createQmlObject(detailSourceTemplate, contact)
89 if (newDetail) {
90 contact.addDetail(newDetail)
91 editContact({ model: root.model,
92 contact: contact,
93 initialFocusSection: "phones",
94 newDetails: [newDetail] })
95 root.addPhoneToContact = ""
96 }
97 }
98 }
99
100 onActionTrigerred: {106 onActionTrigerred: {
101 // "default" action is used inside of the apps (dialer, messaging) to trigger107 // "default" action is used inside of the apps (dialer, messaging) to trigger
102 // actions based on context.108 // actions based on context.
@@ -112,4 +118,27 @@
112 id: contactShareComponent118 id: contactShareComponent
113 ContactSharePage {}119 ContactSharePage {}
114 }120 }
121
122 Loader {
123 id: bottomEdgeLoader
124
125 active: (pageStack.columns > 1)
126 asynchronous: true
127 sourceComponent: ABNewContactBottomEdge {
128 id: bottomEdge
129
130 parent: root
131 height: root.height
132 modelToEdit: root.model
133 hint.flickable: root.flickable
134 pageStack: root.pageStack
135 }
136 }
137
138 Binding {
139 target: pageStack
140 property: 'bottomEdge'
141 value: bottomEdgeLoader.item
142 when: bottomEdgeLoader.status === Loader.Ready
143 }
115}144}
116145
=== added file 'src/imports/ABEmptyState.qml'
--- src/imports/ABEmptyState.qml 1970-01-01 00:00:00 +0000
+++ src/imports/ABEmptyState.qml 2016-01-07 13:19:12 +0000
@@ -0,0 +1,61 @@
1/*
2 * Copyright (C) 2012-2016 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.4
18import Ubuntu.Components 1.3
19
20Column {
21 id: root
22
23 property alias text: emptyStateLabel.text
24
25 spacing: units.gu(2)
26 //implicitHeight: childrenRect.height
27
28 Behavior on visible {
29 SequentialAnimation {
30 PauseAnimation {
31 duration: !root.visible ? 500 : 0
32 }
33 PropertyAction {
34 target: root
35 property: "visible"
36 }
37 }
38 }
39
40 Icon {
41 id: emptyStateIcon
42 anchors.horizontalCenter: emptyStateLabel.horizontalCenter
43 height: units.gu(5)
44 width: units.gu(5)
45 opacity: 0.3
46 name: "contact"
47 }
48 Label {
49 id: emptyStateLabel
50 anchors {
51 left: parent.left
52 right: parent.right
53 }
54 height: paintedHeight
55 text: i18n.tr("Create a new contact by swiping up from the bottom of the screen.")
56 color: "#5d5d5d"
57 fontSize: "x-large"
58 wrapMode: Text.WordWrap
59 horizontalAlignment: Text.AlignHCenter
60 }
61}
062
=== added file 'src/imports/ABMultiColumnEmptyState.qml'
--- src/imports/ABMultiColumnEmptyState.qml 1970-01-01 00:00:00 +0000
+++ src/imports/ABMultiColumnEmptyState.qml 2016-01-07 13:19:12 +0000
@@ -0,0 +1,75 @@
1/*
2 * Copyright (C) 2012-2016 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.4
18import Ubuntu.Components 1.3
19
20
21Page {
22 id: root
23
24 property string headerTitle: i18n.tr("No contacts")
25
26 header: PageHeader {
27 title: root.headerTitle
28 }
29
30 ABEmptyState {
31 id: emptyStateScreen
32
33 anchors {
34 verticalCenter: parent.verticalCenter
35 left: parent.left
36 right: parent.right
37 leftMargin: units.gu(6)
38 rightMargin: units.gu(6)
39 }
40 height: childrenRect.height
41 text: i18n.tr("Create a new contact by swiping up from the bottom of the screen.")
42 }
43
44 Loader {
45 id: bottomEdgeLoader
46
47 active: (pageStack.columns > 1)
48 asynchronous: true
49 sourceComponent: ABNewContactBottomEdge {
50 id: bottomEdge
51
52 parent: root
53 height: root.height
54 modelToEdit: root.pageStack.contactListPage.contactModel
55 hint.flickable: root.flickable
56 pageStack: root.pageStack
57 }
58 }
59
60 Binding {
61 target: pageStack
62 property: 'bottomEdge'
63 value: bottomEdgeLoader.item
64 when: bottomEdgeLoader.status === Loader.Ready
65 }
66
67 Connections {
68 target: pageStack
69 onColumnsChanged: {
70 if (pageStack.columns === 1) {
71 pageStack.removePages(root)
72 }
73 }
74 }
75}
076
=== added file 'src/imports/ABNewContactBottomEdge.qml'
--- src/imports/ABNewContactBottomEdge.qml 1970-01-01 00:00:00 +0000
+++ src/imports/ABNewContactBottomEdge.qml 2016-01-07 13:19:12 +0000
@@ -0,0 +1,89 @@
1/*
2 * Copyright (C) 2012-2015 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.4
18import Ubuntu.Components 1.3
19import Ubuntu.Contacts 0.1 as ContactsUI
20
21BottomEdge {
22 id: bottomEdge
23 objectName: "bottomEdge"
24
25 property var modelToEdit: null
26 property var pageStack: null
27 property var _contactToEdit: null
28 // WORKAROUND: BottomEdge component loads the page async while draging it
29 // this cause a very bad visual.
30 // To avoid that we create it as soon as the component is ready and keep
31 // it invisible until the user start to drag it.
32 property var _realPage: null
33
34 function editContact(contact)
35 {
36 _contactToEdit = contact
37 commit()
38 }
39
40 hint {
41 action: Action {
42 iconName: "contact-new"
43 shortcut: "ctrl+n"
44 enabled: bottomEdge.enabled
45
46 onTriggered: bottomEdge.commit()
47 }
48 }
49
50 contentComponent: Item {
51 id: pageContent
52
53 implicitWidth: bottomEdge.width
54 implicitHeight: bottomEdge.height
55 children: bottomEdge._realPage
56 }
57
58
59 onCommitCompleted: {
60 if (bottomEdge._contactToEdit)
61 editorPage.contact = bottomEdge._contactToEdit
62 bottomEdge._contactToEdit = null
63 }
64
65 onCollapseCompleted: {
66 _realPage = editorPageBottomEdge.createObject(null)
67 }
68
69 Component.onCompleted: {
70 _realPage = editorPageBottomEdge.createObject(null)
71 }
72
73 Component {
74 id: editorPageBottomEdge
75
76 ABContactEditorPage {
77 implicitWidth: bottomEdge.width
78 implicitHeight: bottomEdge.height
79 contact: ContactsUI.ContactsJS.createEmptyContact("", bottomEdge)
80 model: bottomEdge.modelToEdit
81 enabled: bottomEdge.status === BottomEdge.Committed
82 active: bottomEdge.status === BottomEdge.Committed
83 visible: bottomEdge.status !== BottomEdge.Hidden
84 onCanceled: bottomEdge.collapse()
85 onContactSaved: bottomEdge.collapse()
86 pageStack: bottomEdge.pageStack
87 }
88 }
89}
090
=== removed file 'src/imports/BottomEdge.qml'
--- src/imports/BottomEdge.qml 2015-12-14 15:31:50 +0000
+++ src/imports/BottomEdge.qml 1970-01-01 00:00:00 +0000
@@ -1,338 +0,0 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.4
18import Ubuntu.Components 1.3
19
20Item {
21 id: bottomEdge
22
23 readonly property alias content: bottomEdgeLoader.item
24 readonly property bool fullLoaded: bottomEdgeLoader.status == Loader.Ready
25
26 property bool opened: false
27 property Component contentComponent
28 property string iconName
29 property Item flickable
30 property alias backGroundEffectEnabled: darkBg.visible
31
32 signal openBegin
33 signal openEnd
34 signal clicked
35 signal bottomEdgeLoaded
36
37 function open() {
38 bottomEdge.state = "expanded";
39 }
40
41 function close() {
42 bottomEdge.state = "collapsed";
43 }
44
45 Action {
46 text: i18n.tr("New contact")
47 enabled: bottomEdge.visible
48 shortcut: "Ctrl+N"
49 onTriggered: bottomEdge.clicked()
50 }
51
52 Rectangle {
53 id: darkBg
54
55 anchors.fill: parent
56 color: "black"
57 opacity: 0.0
58 }
59
60 Item {
61 id: bottomEdgeBody
62 anchors {
63 left: parent.left
64 right: parent.right
65 }
66 height: bottomEdgeContent.height
67
68 Item {
69 id: bottomEdgeContent
70 anchors {
71 left: parent.left
72 right: parent.right
73 }
74 height: bottomEdgeLoader.height
75
76 Item {
77 id: bottomEdgeShadows
78 anchors.fill: bottomEdgeContent
79
80 BottomEdgeShadow {
81 anchors.bottom: parent.top
82 }
83
84 BottomEdgeShadow {
85 anchors.top: parent.bottom
86 rotation: 180
87 }
88 }
89
90 Rectangle {
91 anchors.fill: parent
92 color: Theme.palette.normal.background
93 }
94
95 Loader {
96 id: bottomEdgeLoader
97 sourceComponent: bottomEdge.contentComponent
98 asynchronous: true
99 active: bottomEdge.enabled
100 onStatusChanged: {
101 if (status === Loader.Ready)
102 bottomEdge.bottomEdgeLoaded()
103 }
104 }
105 }
106
107 BottomEdgeHint {
108 id: bottomEdgeHint
109
110 anchors.bottom: bottomEdgeBody.top
111 iconName: bottomEdge.iconName
112 onClicked: bottomEdge.clicked()
113
114 Connections {
115 target: bottomEdgeDragArea
116 onClosedChanged: {
117 if (!bottomEdgeDragArea.closed) {
118 bottomEdgeHint.state = "Visible";
119 }
120 }
121 }
122
123 Connections {
124 target: flickable
125 onVerticalVelocityChanged: {
126 if (!bottomEdgeDragArea.closed) {
127 return;
128 }
129
130 if (flickable.verticalVelocity > 0) {
131 bottomEdgeHint.state = "Hidden";
132 } else if (flickable.verticalVelocity < 0) {
133 bottomEdgeHint.state = "Visible";
134 }
135 }
136 }
137 }
138 }
139
140
141 state: "collapsed"
142 states: [
143 State {
144 name: "collapsed"
145 ParentChange {
146 target: bottomEdgeContent
147 parent: bottomEdgeBody
148 x: 0
149 y: 0
150 }
151 PropertyChanges {
152 target: bottomEdgeBody
153 y: bottomEdgeDragArea.drag.maximumY
154 }
155 PropertyChanges {
156 target: bottomEdgeContent
157 opacity: 0.0
158 }
159 PropertyChanges {
160 target: darkBg
161 opacity: 0.0
162 }
163 },
164 State {
165 name: "expanded"
166 ParentChange {
167 target: bottomEdgeContent
168 parent: bottomEdge
169 x: 0
170 y: 0
171 }
172 PropertyChanges {
173 target: bottomEdgeContent
174 opacity: 1.0
175 }
176 PropertyChanges {
177 target: bottomEdgeBody
178 y: 0
179 }
180 PropertyChanges {
181 target: bottomEdgeShadows
182 opacity: 0.0
183 visible: true
184 }
185 PropertyChanges {
186 target: darkBg
187 opacity: 0.8
188 }
189 },
190 State {
191 name: "floating"
192 when: bottomEdgeDragArea.drag.active
193 PropertyChanges {
194 target: bottomEdgeContent
195 opacity: 1.0
196 }
197 PropertyChanges {
198 target: darkBg
199 opacity: bottomEdgeBody.y > 0 ? 0.8 - (bottomEdgeBody.y / bottomEdgeDragArea.drag.maximumY) : 0.8
200 }
201 }
202 ]
203
204 transitions: [
205 Transition {
206 to: "collapsed"
207 SequentialAnimation {
208 alwaysRunToEnd: true
209 ParallelAnimation {
210 ParentAnimation {
211 UbuntuNumberAnimation {
212 properties: "x,y"
213 duration: UbuntuAnimation.SlowDuration
214 target: bottomEdgeContent
215 }
216 }
217 UbuntuNumberAnimation {
218 target: bottomEdgeBody
219 property: "y"
220 duration: UbuntuAnimation.SlowDuration
221 }
222 UbuntuNumberAnimation {
223 target: darkBg
224 property: "opacity"
225 duration: UbuntuAnimation.SlowDuration
226 }
227 }
228 PropertyAction {
229 target: bottomEdgeContent
230 property: "opacity"
231 }
232 ScriptAction {
233 script: {
234 bottomEdgeLoader.active = false
235 bottomEdgeLoader.active = true
236 bottomEdge.opened = false
237 }
238 }
239 }
240 },
241 Transition {
242 to: "expanded"
243 SequentialAnimation {
244 alwaysRunToEnd: true
245 ParallelAnimation {
246 ScriptAction {
247 script: bottomEdge.openBegin()
248 }
249 ParentAnimation {
250 UbuntuNumberAnimation {
251 properties: "x,y"
252 duration: UbuntuAnimation.SlowDuration
253 target: bottomEdgeContent
254 }
255 }
256 UbuntuNumberAnimation {
257 target: bottomEdgeShadows
258 property: "opacity"
259 duration: UbuntuAnimation.SlowDuration
260 }
261 UbuntuNumberAnimation {
262 target: darkBg
263 property: "opacity"
264 duration: UbuntuAnimation.SlowDuration
265 }
266 }
267 UbuntuNumberAnimation {
268 target: bottomEdgeContent
269 property: "opacity"
270 duration: UbuntuAnimation.FastDuration
271 }
272 ScriptAction {
273 script: {
274 bottomEdge.opened = true
275 bottomEdge.openEnd()
276 }
277
278 }
279 }
280 }
281 ]
282
283 MouseArea {
284 id: bottomEdgeDragArea
285 objectName: "bottomEdgeDragArea"
286
287 property real previousY: -1
288 property string dragDirection: "None"
289 property bool closed: drag.target.y == bottomEdgeDragArea.drag.maximumY
290 && !bottomEdgeDragArea.pressed
291
292 preventStealing: true
293 propagateComposedEvents: true
294 drag {
295 axis: Drag.YAxis
296 target: bottomEdgeBody
297 minimumY: 0
298 maximumY: bottomEdge.height
299 }
300
301 anchors {
302 left: parent.left
303 right: parent.right
304 bottom: parent.bottom
305 }
306 height: bottomEdgeHint.height
307
308 onPressed: {
309 previousY = mouse.y;
310 }
311
312 onReleased: {
313 if (dragDirection === "BottomToTop") {
314 bottomEdge.state = "expanded";
315 } else {
316 bottomEdge.state = "collapsed";
317 }
318 previousY = -1;
319 dragDirection = "None";
320 }
321
322 onMouseYChanged: {
323 var yOffset = previousY - mouseY;
324 // skip if was a small move
325 if (Math.abs(yOffset) <= units.gu(2)) {
326 return;
327 }
328 previousY = mouseY;
329 dragDirection = yOffset > 0 ? "BottomToTop" : "TopToBottom";
330 }
331 }
332
333 Binding {
334 target: bottomEdge
335 property: 'visible'
336 value: bottomEdge.enabled && !bottomEdge.opened
337 }
338}
3390
=== removed file 'src/imports/BottomEdgeShadow.qml'
--- src/imports/BottomEdgeShadow.qml 2015-09-10 14:47:38 +0000
+++ src/imports/BottomEdgeShadow.qml 1970-01-01 00:00:00 +0000
@@ -1,31 +0,0 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.4
18import Ubuntu.Components 1.3
19
20Rectangle {
21 id: bottomEdgeShadow
22 anchors {
23 left: parent.left
24 right: parent.right
25 }
26 height: units.gu(1)
27 gradient: Gradient {
28 GradientStop { position: 0.0; color: Qt.rgba(0.0, 0.0, 0.0, 0.0) }
29 GradientStop { position: 1.0; color: Qt.rgba(0.0, 0.0, 0.0, 0.3) }
30 }
31}
320
=== modified file 'src/imports/CMakeLists.txt'
--- src/imports/CMakeLists.txt 2015-11-19 14:41:18 +0000
+++ src/imports/CMakeLists.txt 2016-01-07 13:19:12 +0000
@@ -4,10 +4,11 @@
4 ABContactListPage.qml4 ABContactListPage.qml
5 ABContactEditorPage.qml5 ABContactEditorPage.qml
6 ABContactViewPage.qml6 ABContactViewPage.qml
7 ABEmptyState.qml
8 ABNewContactBottomEdge.qml
9 ABMultiColumnEmptyState.qml
7 ContentHubProxy.qml10 ContentHubProxy.qml
8 MainWindow.qml11 MainWindow.qml
9 BottomEdgeShadow.qml
10 BottomEdge.qml
11)12)
1213
13install(FILES ${ADDRESS_BOOK_APP_QMLS}14install(FILES ${ADDRESS_BOOK_APP_QMLS}
1415
=== modified file 'src/imports/MainWindow.qml'
--- src/imports/MainWindow.qml 2015-12-10 19:13:20 +0000
+++ src/imports/MainWindow.qml 2016-01-07 13:19:12 +0000
@@ -18,6 +18,8 @@
18import Ubuntu.Components 1.318import Ubuntu.Components 1.3
19import Ubuntu.Components.Popups 1.3 as Popups19import Ubuntu.Components.Popups 1.3 as Popups
2020
21import Unity.InputInfo 0.1
22
21MainView {23MainView {
22 id: mainWindow24 id: mainWindow
23 objectName: "addressBookAppMainWindow"25 objectName: "addressBookAppMainWindow"
@@ -47,16 +49,6 @@
47 }49 }
48 }50 }
4951
50 function addphone(contactId, phoneNumber)
51 {
52 mainStack.resetStack()
53 if (mainStack.contactListPage) {
54 mainStack.contactListPage.addPhoneToContact(contactId, phoneNumber)
55 } else {
56 console.error("Add phone to contact requested but ContactListPage not loaded")
57 }
58 }
59
60 function pick(single)52 function pick(single)
61 {53 {
62 console.debug("Pick mode:" + single)54 console.debug("Pick mode:" + single)
@@ -88,24 +80,35 @@
88 }80 }
89 }81 }
9082
91 function addnewphone(phoneNumer)
92 {
93 mainStack.resetStack()
94 if (mainStack.contactListPage) {
95 mainStack.contactListPage.addNewPhone(phoneNumer)
96 } else {
97 console.error("Add new phone requested but ContactListPage not loaded")
98 }
99 }
100
101 width: units.gu(90)83 width: units.gu(90)
102 height: units.gu(71)84 height: units.gu(71)
103 anchorToKeyboard: false85 anchorToKeyboard: false
10486
87 InputDeviceModel {
88 id: miceModel
89 deviceFilter: InputInfo.Mouse
90 }
91
92 InputDeviceModel {
93 id: touchPadModel
94 deviceFilter: InputInfo.TouchPad
95 }
96
97 InputDeviceModel {
98 id: keyboardsModel
99 deviceFilter: InputInfo.Keyboard
100 }
101
102
105 AdaptivePageLayout {103 AdaptivePageLayout {
106 id: mainStack104 id: mainStack
105 objectName: "mainStack"
107106
108 property var contactListPage: null107 property var contactListPage: null
108 property var bottomEdge: null
109 readonly property bool bottomEdgeOpened: (bottomEdge && bottomEdge.status === BottomEdge.Committed)
110 readonly property bool hasMouse: ((miceModel.count > 0) || (touchPadModel.count > 0))
111 readonly property bool hasKeyboard: (keyboardsModel.count > 0)
109112
110 function resetStack()113 function resetStack()
111 {114 {
@@ -145,7 +148,7 @@
145 anchors.fill: parent148 anchors.fill: parent
146 layouts: [149 layouts: [
147 PageColumnsLayout {150 PageColumnsLayout {
148 when: mainStack.width >= units.gu(80)151 when: mainStack.width >= units.gu(70)
149 PageColumn {152 PageColumn {
150 maximumWidth: units.gu(50)153 maximumWidth: units.gu(50)
151 minimumWidth: units.gu(40)154 minimumWidth: units.gu(40)
@@ -163,6 +166,14 @@
163 }166 }
164 ]167 ]
165168
169 onColumnsChanged: {
170 if (mainStack.columns > 1) {
171 if (mainStack.contactListPage)
172 mainStack.contactListPage.fetchContact()
173 else
174 mainStack.addPageToNextColumn(contactPage, Qt.resolvedUrl("./ABMultiColumnEmptyState.qml"))
175 }
176 }
166 }177 }
167178
168 ABContactListPage {179 ABContactListPage {
@@ -177,6 +188,16 @@
177 mainWindow.applicationReady()188 mainWindow.applicationReady()
178 }189 }
179190
191 // WORKAROUND: Due the missing feature on SDK, they can not detect if
192 // there is a mouse attached to device or not. And this will cause the
193 // bootom edge component to not work correct on desktop.
194 // We will consider that a mouse is always attached until it get implement on SDK.
195 Binding {
196 target: QuickUtils
197 property: "mouseAttached"
198 value: mainStack.hasMouse
199 }
200
180 Component {201 Component {
181 id: errorDialog202 id: errorDialog
182203
183204
=== modified file 'src/imports/Settings/SettingsPage.qml'
--- src/imports/Settings/SettingsPage.qml 2015-12-16 18:35:33 +0000
+++ src/imports/Settings/SettingsPage.qml 2016-01-07 13:19:12 +0000
@@ -87,12 +87,12 @@
87 // FIXME: Using a private property here. This uses the old list item and the only way to change the text87 // FIXME: Using a private property here. This uses the old list item and the only way to change the text
88 // color is with this property.88 // color is with this property.
89 // We should remove it when update the app to the new ListItem.89 // We should remove it when update the app to the new ListItem.
90 __foregroundColor: (activeFocus && (pageStack.columns > 1)) ? Theme.palette.normal.foregroundText :90 __foregroundColor: (activeFocus && pageStack.hasKeyboard) ? Theme.palette.normal.foregroundText :
91 Theme.palette.normal.foreground91 Theme.palette.normal.foreground
92 Rectangle {92 Rectangle {
93 color: UbuntuColors.orange93 color: UbuntuColors.orange
94 anchors.fill: parent94 anchors.fill: parent
95 visible:addGoogleAccountItem.activeFocus95 visible:addGoogleAccountItem.activeFocus && pageStack.hasKeyboard
96 z: -196 z: -1
97 }97 }
98 }98 }
9999
=== modified file 'src/imports/Ubuntu/AddressBook/Base/ContactDetailGroupBase.qml'
--- src/imports/Ubuntu/AddressBook/Base/ContactDetailGroupBase.qml 2015-11-19 16:38:36 +0000
+++ src/imports/Ubuntu/AddressBook/Base/ContactDetailGroupBase.qml 2016-01-07 13:19:12 +0000
@@ -33,9 +33,8 @@
33 property int minimumHeight: 033 property int minimumHeight: 0
34 property bool loaded: false34 property bool loaded: false
35 property bool showEmpty: true35 property bool showEmpty: true
36 property bool forceFocusOnFieldCreation: false
3736
38 signal newFieldAdded(var index)37 signal newFieldAdded(int fieldIndex, QtObject field)
3938
40 function reloadDetails(clearFields)39 function reloadDetails(clearFields)
41 {40 {
@@ -145,10 +144,10 @@
145 if (status === Loader.Ready) {144 if (status === Loader.Ready) {
146 var newFields = root.inputFields145 var newFields = root.inputFields
147 newFields.push(detailItem.item)146 newFields.push(detailItem.item)
148 root.newFieldAdded(detailItem.item)147
149 root.inputFields = newFields148 root.inputFields = newFields
150 if (root.loaded && root.forceFocusOnFieldCreation) {149 if (root.loaded) {
151 item.forceActiveFocus()150 root.newFieldAdded(detailItem.item, item)
152 }151 }
153 }152 }
154 }153 }
155154
=== modified file 'src/imports/Ubuntu/AddressBook/Base/KeyboardRectangle.qml'
--- src/imports/Ubuntu/AddressBook/Base/KeyboardRectangle.qml 2015-10-26 13:18:11 +0000
+++ src/imports/Ubuntu/AddressBook/Base/KeyboardRectangle.qml 2016-01-07 13:19:12 +0000
@@ -18,10 +18,13 @@
1818
19Item {19Item {
20 id: keyboardRect20 id: keyboardRect
21
22 property bool active: true
23
21 anchors.left: parent.left24 anchors.left: parent.left
22 anchors.right: parent.right25 anchors.right: parent.right
23 anchors.bottom: parent.bottom26 anchors.bottom: parent.bottom
24 height: Qt.inputMethod.visible ? Qt.inputMethod.keyboardRectangle.height : 027 height: active && Qt.inputMethod.visible ? Qt.inputMethod.keyboardRectangle.height : 0
2528
26 states: [29 states: [
27 State {30 State {
2831
=== modified file 'src/imports/Ubuntu/AddressBook/ContactEditor/ComboButtonAddField.qml'
--- src/imports/Ubuntu/AddressBook/ContactEditor/ComboButtonAddField.qml 2015-10-26 13:18:11 +0000
+++ src/imports/Ubuntu/AddressBook/ContactEditor/ComboButtonAddField.qml 2016-01-07 13:19:12 +0000
@@ -106,8 +106,8 @@
106 // make sure that the signal will be fired after the item collapse106 // make sure that the signal will be fired after the item collapse
107 onHeightChanged: {107 onHeightChanged: {
108 if (!expanded && (selectedDetail !== -1) && (height === collapsedHeight)) {108 if (!expanded && (selectedDetail !== -1) && (height === collapsedHeight)) {
109 fieldSelected(root.nameFromEnum(selectedDetail), root.qmlTypeFromEnum(selectedDetail))109 root.fieldSelected(root.nameFromEnum(root.selectedDetail), root.qmlTypeFromEnum(root.selectedDetail))
110 selectedDetail = -1110 root.selectedDetail = -1
111 }111 }
112 }112 }
113113
114114
=== modified file 'src/imports/Ubuntu/AddressBook/ContactEditor/ContactDetailAvatarEditor.qml'
--- src/imports/Ubuntu/AddressBook/ContactEditor/ContactDetailAvatarEditor.qml 2015-11-24 12:18:17 +0000
+++ src/imports/Ubuntu/AddressBook/ContactEditor/ContactDetailAvatarEditor.qml 2016-01-07 13:19:12 +0000
@@ -144,7 +144,6 @@
144 }144 }
145145
146 Component.onDestruction: {146 Component.onDestruction: {
147 console.debug("Delete temporary avatar image:" + root.temporaryAvatar)
148 Contacts.removeFile("file:///" + root.temporaryAvatar)147 Contacts.removeFile("file:///" + root.temporaryAvatar)
149 root.temporaryAvatar = ""148 root.temporaryAvatar = ""
150 }149 }
151150
=== modified file 'src/imports/Ubuntu/AddressBook/ContactEditor/ContactDetailGroupWithTypeEditor.qml'
--- src/imports/Ubuntu/AddressBook/ContactEditor/ContactDetailGroupWithTypeEditor.qml 2015-11-19 16:38:36 +0000
+++ src/imports/Ubuntu/AddressBook/ContactEditor/ContactDetailGroupWithTypeEditor.qml 2016-01-07 13:19:12 +0000
@@ -98,7 +98,6 @@
98 return changed98 return changed
99 }99 }
100100
101 forceFocusOnFieldCreation: true
102 headerDelegate: Label {101 headerDelegate: Label {
103 id: header102 id: header
104103
105104
=== modified file 'src/imports/Ubuntu/AddressBook/ContactEditor/ContactDetailWithTypeEditor.qml'
--- src/imports/Ubuntu/AddressBook/ContactEditor/ContactDetailWithTypeEditor.qml 2015-11-10 19:03:36 +0000
+++ src/imports/Ubuntu/AddressBook/ContactEditor/ContactDetailWithTypeEditor.qml 2016-01-07 13:19:12 +0000
@@ -33,6 +33,7 @@
33 property variant placeholderTexts: []33 property variant placeholderTexts: []
34 property int inputMethodHints: Qt.ImhNone34 property int inputMethodHints: Qt.ImhNone
35 property bool usePhoneFormat: false35 property bool usePhoneFormat: false
36 readonly property alias repeater: fieldRepeater
3637
37 function selectType(type) {38 function selectType(type) {
38 detailTypeSelector.selectItem(type)39 detailTypeSelector.selectItem(type)
@@ -96,7 +97,6 @@
9697
97 detail: root.detail98 detail: root.detail
98 field: modelData99 field: modelData
99 focus: true
100 placeholderText: root.placeholderTexts[index]100 placeholderText: root.placeholderTexts[index]
101 inputMethodHints: root.inputMethodHints101 inputMethodHints: root.inputMethodHints
102 autoFormat: root.usePhoneFormat102 autoFormat: root.usePhoneFormat
103103
=== modified file 'src/imports/Ubuntu/AddressBook/ContactEditor/ContactEditorPage.qml'
--- src/imports/Ubuntu/AddressBook/ContactEditor/ContactEditorPage.qml 2015-12-18 13:16:55 +0000
+++ src/imports/Ubuntu/AddressBook/ContactEditor/ContactEditorPage.qml 2016-01-07 13:19:12 +0000
@@ -33,11 +33,15 @@
3333
34 property string initialFocusSection: ""34 property string initialFocusSection: ""
35 property var newDetails: []35 property var newDetails: []
36 property list<QtObject> leadingActions
37 property alias headerActions: trailingBar.actions
3638
37 readonly property bool isNewContact: contact && (contact.contactId === "qtcontacts:::")39 readonly property bool isNewContact: contact && (contact.contactId === "qtcontacts:::")
38 readonly property bool isContactValid: !avatarEditor.busy && (!nameEditor.isEmpty() || !phonesEditor.isEmpty())40 readonly property bool isContactValid: !avatarEditor.busy && (!nameEditor.isEmpty() || !phonesEditor.isEmpty())
41 readonly property alias editorFlickable: scrollArea
3942
40 signal contactSaved(var contact);43 signal contactSaved(var contact);
44 signal canceled()
4145
42 function cancel() {46 function cancel() {
43 for (var i = 0; i < contactEditor.newDetails.length; ++i) {47 for (var i = 0; i < contactEditor.newDetails.length; ++i) {
@@ -51,11 +55,12 @@
51 field.cancel()55 field.cancel()
52 }56 }
53 }57 }
54 if (pageStack.removePages) {58 if (pageStack && pageStack.removePages) {
55 pageStack.removePages(contactEditor)59 pageStack.removePages(contactEditor)
56 } else {60 } else if (pageStack) {
57 pageStack.pop()61 pageStack.pop()
58 }62 }
63 contactEditor.canceled()
59 }64 }
6065
61 function save() {66 function save() {
@@ -100,18 +105,25 @@
100 }105 }
101 }106 }
102107
103 function makeMeVisible(item) {108 function idleMakeMeVisible(item) {
104 if (!enabled || !item) {109 if (!enabled || !item) {
105 return110 return
106 }111 }
107112
108 activeItem = item113 activeItem = item
109 var position = scrollArea.contentItem.mapFromItem(item, 0, activeItem.y);114 timerMakemakeMeVisible.restart()
110115 }
116
117 function makeMeVisible(item) {
118 if (!item)
119 return
120
121 var position = activeItem.mapToItem(editEditor, item.x, item.y);
111 // check if the item is already visible122 // check if the item is already visible
112 var bottomY = scrollArea.contentY + scrollArea.height123 var bottomY = scrollArea.contentY + scrollArea.height
113 var itemBottom = position.y + (item.height * 3) // extra margin124 var itemBottom = position.y + (item.height * 3) // extra margin
114 if (position.y >= scrollArea.contentY && itemBottom <= bottomY) {125 if (position.y >= scrollArea.contentY && itemBottom <= bottomY) {
126 Qt.inputMethod.show()
115 return;127 return;
116 }128 }
117129
@@ -123,7 +135,9 @@
123 // if it is hidden at the top, also show it135 // if it is hidden at the top, also show it
124 scrollArea.contentY = position.y;136 scrollArea.contentY = position.y;
125 }137 }
138
126 scrollArea.returnToBounds()139 scrollArea.returnToBounds()
140 Qt.inputMethod.show()
127 }141 }
128142
129 function ready()143 function ready()
@@ -135,6 +149,7 @@
135 contactEditor.focusToLastPhoneField()149 contactEditor.focusToLastPhoneField()
136 break;150 break;
137 case "name":151 case "name":
152 default:
138 nameEditor.fieldDelegates[0].forceActiveFocus()153 nameEditor.fieldDelegates[0].forceActiveFocus()
139 break;154 break;
140 }155 }
@@ -146,9 +161,42 @@
146 lastPhoneField.forceActiveFocus()161 lastPhoneField.forceActiveFocus()
147 }162 }
148163
149 title: isNewContact ? i18n.dtr("address-book-app", "New contact") : i18n.dtr("address-book-app", "Edit")164 function focusToFirstEntry(field)
165 {
166 var itemToFocus = field
167 if (field.repeater)
168 itemToFocus = field.repeater.itemAt(0)
169
170 if (itemToFocus) {
171 root.idleMakeMeVisible(itemToFocus)
172 itemToFocus.forceActiveFocus()
173 }
174 }
175
176 Timer {
177 id: timerMakemakeMeVisible
178
179 interval: 100
180 repeat: false
181 running: false
182 onTriggered: root.makeMeVisible(root.activeItem)
183 }
184
185 header: PageHeader {
186 id: pageHeader
187
188 title: isNewContact ? i18n.dtr("address-book-app", "New contact") : i18n.dtr("address-book-app", "Edit")
189 trailingActionBar {
190 id: trailingBar
191 }
192 leadingActionBar {
193 id: leadingBar
194 actions: contactEditor.leadingActions
195 }
196 }
197
150 enabled: false198 enabled: false
151199 flickable: null
152 Timer {200 Timer {
153 id: focusTimer201 id: focusTimer
154202
@@ -158,7 +206,6 @@
158 onTriggered: contactEditor.ready()206 onTriggered: contactEditor.ready()
159 }207 }
160208
161 flickable: null
162 Flickable {209 Flickable {
163 id: scrollArea210 id: scrollArea
164 objectName: "scrollArea"211 objectName: "scrollArea"
@@ -169,17 +216,13 @@
169 anchors{216 anchors{
170 left: parent.left217 left: parent.left
171 top: parent.top218 top: parent.top
219 topMargin: pageHeader.height
172 right: parent.right220 right: parent.right
173 bottom: keyboardRectangle.top221 bottom: keyboardRectangle.top
174 }222 }
175 contentHeight: contents.height + units.gu(2)223 contentHeight: contents.height + units.gu(2)
176 contentWidth: parent.width224 contentWidth: parent.width
177225
178 //after add a new field we need to wait for the contentHeight to change to scroll to the correct position
179 onContentHeightChanged: {
180 contactEditor.makeMeVisible(contactEditor.activeItem)
181 }
182
183 Column {226 Column {
184 id: contents227 id: contents
185228
@@ -242,6 +285,7 @@
242 right: parent.right285 right: parent.right
243 }286 }
244 height: implicitHeight287 height: implicitHeight
288 onNewFieldAdded: root.focusToFirstEntry(field)
245 }289 }
246290
247 ContactDetailEmailsEditor {291 ContactDetailEmailsEditor {
@@ -254,6 +298,7 @@
254 right: parent.right298 right: parent.right
255 }299 }
256 height: implicitHeight300 height: implicitHeight
301 onNewFieldAdded: root.focusToFirstEntry(field)
257 }302 }
258303
259 ContactDetailOnlineAccountsEditor {304 ContactDetailOnlineAccountsEditor {
@@ -266,6 +311,7 @@
266 right: parent.right311 right: parent.right
267 }312 }
268 height: implicitHeight313 height: implicitHeight
314 onNewFieldAdded: root.focusToFirstEntry(field)
269 }315 }
270316
271 ContactDetailAddressesEditor {317 ContactDetailAddressesEditor {
@@ -278,6 +324,7 @@
278 right: parent.right324 right: parent.right
279 }325 }
280 height: implicitHeight326 height: implicitHeight
327 onNewFieldAdded: root.focusToFirstEntry(field)
281 }328 }
282329
283 ContactDetailOrganizationsEditor {330 ContactDetailOrganizationsEditor {
@@ -290,6 +337,7 @@
290 right: parent.right337 right: parent.right
291 }338 }
292 height: implicitHeight339 height: implicitHeight
340 onNewFieldAdded: root.focusToFirstEntry(field)
293 }341 }
294342
295 ContactDetailSyncTargetEditor {343 ContactDetailSyncTargetEditor {
@@ -332,6 +380,7 @@
332 margins: units.gu(2)380 margins: units.gu(2)
333 }381 }
334 height: implicitHeight382 height: implicitHeight
383 activeFocusOnPress: false
335 onHeightChanged: {384 onHeightChanged: {
336 if (expanded && (height === expandedHeight) && !scrollArea.atYEnd) {385 if (expanded && (height === expandedHeight) && !scrollArea.atYEnd) {
337 moveToBottom.start()386 moveToBottom.start()
@@ -343,9 +392,11 @@
343392
344 target: scrollArea393 target: scrollArea
345 property: "contentY"394 property: "contentY"
346 from: scrollArea.contentY395 to: scrollArea.contentHeight - scrollArea.height
347 to: Math.min(scrollArea.contentHeight - scrollArea.height,396 onStopped: {
348 scrollArea.contentY + (addNewFieldButton.height - addNewFieldButton.collapsedHeight - units.gu(3)))397 scrollArea.returnToBounds()
398 addNewFieldButton.forceActiveFocus()
399 }
349 }400 }
350401
351 onFieldSelected: {402 onFieldSelected: {
@@ -406,8 +457,11 @@
406 id: keyboardRectangle457 id: keyboardRectangle
407458
408 onHeightChanged: {459 onHeightChanged: {
409 if (activeItem) {460 if (addNewFieldButton.expanded) {
410 makeMeVisible(activeItem)461 scrollArea.contentY = scrollArea.contentHeight - scrollArea.height
462 scrollArea.returnToBounds()
463 } else if (activeItem) {
464 idleMakeMeVisible(activeItem)
411 }465 }
412 }466 }
413 }467 }
@@ -493,6 +547,8 @@
493 contactEditor.pageStack.pop() // view page547 contactEditor.pageStack.pop() // view page
494 }548 }
495 }549 }
550 if (contactEditor.pageStack.primaryPage)
551 contactEditor.pageStack.primaryPage.forceActiveFocus()
496 }552 }
497 }553 }
498 }554 }
499555
=== modified file 'src/imports/Ubuntu/AddressBook/ContactEditor/TextInputDetail.qml'
--- src/imports/Ubuntu/AddressBook/ContactEditor/TextInputDetail.qml 2015-11-25 17:31:33 +0000
+++ src/imports/Ubuntu/AddressBook/ContactEditor/TextInputDetail.qml 2016-01-07 13:19:12 +0000
@@ -47,27 +47,18 @@
4747
48 //FIXME: Move this property to TextField as soon as the SDK get ported to QtQuick 2.248 //FIXME: Move this property to TextField as soon as the SDK get ported to QtQuick 2.2
49 activeFocusOnTab: true49 activeFocusOnTab: true
50
51 // WORKAROUND: For some reason TextField.focus property get reset to false
52 // we need do a deep investigation on that
53 Binding {
54 target: field
55 property: "focus"
56 value: visible
57 }
58
59 onActiveFocusChanged: {
60 if (activeFocus && field.visible) {
61 field.forceActiveFocus()
62 }
63 }
64
65 onOriginalValueChanged: {50 onOriginalValueChanged: {
66 if (originalValue && (originalValue !== "")) {51 if (originalValue && (originalValue !== "")) {
67 field.text = originalValue52 field.text = originalValue
68 }53 }
69 }54 }
7055
56 // propage focus to text field
57 onActiveFocusChanged: {
58 if (activeFocus)
59 field.forceActiveFocus()
60 }
61
71 PhoneNumberField {62 PhoneNumberField {
72 id: field63 id: field
7364
7465
=== modified file 'src/imports/Ubuntu/AddressBook/ContactShare/ContactSharePage.qml'
--- src/imports/Ubuntu/AddressBook/ContactShare/ContactSharePage.qml 2015-10-26 13:18:11 +0000
+++ src/imports/Ubuntu/AddressBook/ContactShare/ContactSharePage.qml 2016-01-07 13:19:12 +0000
@@ -50,13 +50,21 @@
50 if (exporter.activeTransfer) {50 if (exporter.activeTransfer) {
51 exporter.activeTransfer.state = ContentHub.ContentTransfer.Aborted51 exporter.activeTransfer.state = ContentHub.ContentTransfer.Aborted
52 }52 }
53 pageStack.removePages(root)53 if (root.pageStack.removePages)
54 root.pageStack.removePages(root)
55 else
56 root.pageStack.pop()
54 }57 }
55 }58 }
5659
57 ContactExporter {60 ContactExporter {
58 id: exporter61 id: exporter
5962
60 onDone: pageStack.removePages(root)63 onDone: {
64 if (root.pageStack.removePages)
65 root.pageStack.removePages(root)
66 else
67 root.pageStack.pop()
68 }
61 }69 }
62}70}
6371
=== modified file 'src/imports/Ubuntu/AddressBook/ContactView/ContactViewPage.qml'
--- src/imports/Ubuntu/AddressBook/ContactView/ContactViewPage.qml 2015-12-10 19:13:20 +0000
+++ src/imports/Ubuntu/AddressBook/ContactView/ContactViewPage.qml 2016-01-07 13:19:12 +0000
@@ -29,6 +29,7 @@
29 property alias extensions: extensionsContents.children29 property alias extensions: extensionsContents.children
30 property alias model: contactFetch.model30 property alias model: contactFetch.model
31 property alias editable: contactDetailAvatar.editable31 property alias editable: contactDetailAvatar.editable
32 property alias headerActions: trailingBar.actions
3233
33 signal contactFetched(QtObject contact)34 signal contactFetched(QtObject contact)
34 signal contactRemoved()35 signal contactRemoved()
@@ -41,12 +42,20 @@
41 }42 }
42 }43 }
4344
44 title: contact ? ContactsJS.formatToDisplay(contact, i18n.dtr("address-book-app", "No name")) : ""45 header: PageHeader {
46 id: pageHeader
47
48 flickable: flickable
49 title: contact ? ContactsJS.formatToDisplay(contact, i18n.dtr("address-book-app", "No name")) : ""
50 trailingActionBar {
51 id: trailingBar
52 }
53 }
4554
46 Connections {55 Connections {
47 target: contact56 target: contact
48 onContactChanged: {57 onContactChanged: {
49 root.title = ContactsJS.formatToDisplay(contact, i18n.dtr("address-book-app", "No name"))58 pageHeader.title = ContactsJS.formatToDisplay(contact, i18n.dtr("address-book-app", "No name"))
50 }59 }
51 }60 }
5261
@@ -88,11 +97,13 @@
88 }97 }
89 }98 }
9099
100
91 Flickable {101 Flickable {
92 id: flickable102 id: flickable
93103
94 flickableDirection: Flickable.VerticalFlick104 flickableDirection: Flickable.VerticalFlick
95 anchors.fill: parent105 anchors.fill: parent
106 clip: true
96 //WORKAROUND: There is a bug on SDK page that causes the page to appear flicked with small contents107 //WORKAROUND: There is a bug on SDK page that causes the page to appear flicked with small contents
97 // see bug #1223050108 // see bug #1223050
98 contentHeight: Math.max(contents.height, parent.height) + units.gu(2)109 contentHeight: Math.max(contents.height, parent.height) + units.gu(2)
99110
=== modified file 'src/imports/Ubuntu/Contacts/ContactListView.qml'
--- src/imports/Ubuntu/Contacts/ContactListView.qml 2015-12-02 17:10:53 +0000
+++ src/imports/Ubuntu/Contacts/ContactListView.qml 2016-01-07 13:19:12 +0000
@@ -202,12 +202,6 @@
202 */202 */
203 property bool showAddNewButton: false203 property bool showAddNewButton: false
204 /*!204 /*!
205 \qmlproperty bool prepareNewContact
206
207 This property holds if space for a draft new contact should be made available or not
208 */
209 property bool prepareNewContact: false
210 /*!
211 \qmlproperty bool showNewContact205 \qmlproperty bool showNewContact
212206
213 This property holds if a draft new contact should be visible or not207 This property holds if a draft new contact should be visible or not
@@ -407,6 +401,7 @@
407 }401 }
408 anchors.fill: parent402 anchors.fill: parent
409403
404
410 // WORKAROUND: The SDK header causes the contactY to move to a wrong postion405 // WORKAROUND: The SDK header causes the contactY to move to a wrong postion
411 // calling the positionViewAtBeginning after the list created fix that406 // calling the positionViewAtBeginning after the list created fix that
412 Timer {407 Timer {
@@ -424,15 +419,18 @@
424 right: parent.right419 right: parent.right
425 }420 }
426421
427 Connections {422 Binding {
428 target: root423 target: view
429 onPrepareNewContactChanged: {424 property: 'contentY'
430 if (root.prepareNewContact) {425 value: -view.headerItem.height
431 view.contentY = Qt.binding(function() {return -view.headerItem.height});426 when: root.showNewContact
432 } else {427 }
433 view.contentY = view.contentY;428
434 }429 Binding {
435 }430 target: view
431 property: 'currentIndex'
432 value: -1
433 when: root.showNewContact
436 }434 }
437435
438 // AddNewButton436 // AddNewButton
@@ -461,10 +459,9 @@
461 }459 }
462 }460 }
463 selected: true461 selected: true
464 visible: root.prepareNewContact462 visible: root.showNewContact
465 height: root.prepareNewContact ? defaultHeight : 0463 height: root.showNewContact ? defaultHeight : 0
466 Behavior on height {UbuntuNumberAnimation {}}464 Behavior on height {UbuntuNumberAnimation {}}
467 opacity: root.showNewContact ? 1.0 : 0.0
468 }465 }
469466
470 Column {467 Column {
471468
=== modified file 'src/imports/Ubuntu/Contacts/ContactSimpleListView.qml'
--- src/imports/Ubuntu/Contacts/ContactSimpleListView.qml 2015-12-10 19:13:29 +0000
+++ src/imports/Ubuntu/Contacts/ContactSimpleListView.qml 2016-01-07 13:19:12 +0000
@@ -270,9 +270,9 @@
270 flicking: contactListView.flicking270 flicking: contactListView.flicking
271 width: parent.width271 width: parent.width
272 selected: (contactListView.multiSelectionEnabled && contactListView.isSelected(contactDelegate))272 selected: (contactListView.multiSelectionEnabled && contactListView.isSelected(contactDelegate))
273 || (contactListView.highlightSelected && (contactListView.currentIndex == index))273 || (!contactListView.isInSelectionMode && contactListView.highlightSelected && (contactListView.currentIndex == index))
274 selectedColor: contactListView.parent.activeFocus && !contactListView.isInSelectionMode ? UbuntuColors.orange :274 selectedColor: contactListView.parent.activeFocus && !contactListView.isInSelectionMode && contactListView.highlightSelected ?
275 Theme.palette.selected.background275 UbuntuColors.orange : Theme.palette.selected.background
276 selectionMode: contactListView.isInSelectionMode276 selectionMode: contactListView.isInSelectionMode
277 defaultAvatarUrl: contactListView.defaultAvatarImageUrl277 defaultAvatarUrl: contactListView.defaultAvatarImageUrl
278 isCurrentItem: ListView.isCurrentItem278 isCurrentItem: ListView.isCurrentItem
279279
=== modified file 'src/imports/Ubuntu/Contacts/ListItemWithActions.qml'
--- src/imports/Ubuntu/Contacts/ListItemWithActions.qml 2015-11-10 19:51:19 +0000
+++ src/imports/Ubuntu/Contacts/ListItemWithActions.qml 2016-01-07 13:19:12 +0000
@@ -314,6 +314,23 @@
314 }314 }
315315
316 SequentialAnimation {316 SequentialAnimation {
317 id: clickAnimation
318
319 running: false
320 alwaysRunToEnd: true
321 PropertyAnimation {
322 target: main
323 property: "color"
324 to: root.selectedColor
325 }
326 PropertyAction {
327 target: main
328 property: "color"
329 value: root.selected ? root.selectedColor : root.color
330 }
331 }
332
333 SequentialAnimation {
317 id: triggerAction334 id: triggerAction
318335
319 property var currentItem: root.activeItem ? root.activeItem.image : null336 property var currentItem: root.activeItem ? root.activeItem.image : null
@@ -424,6 +441,8 @@
424 onClicked: {441 onClicked: {
425 if (main.x === 0) {442 if (main.x === 0) {
426 root.itemClicked(mouse)443 root.itemClicked(mouse)
444 if (!root.selected)
445 clickAnimation.start()
427 } else if (main.x > 0) {446 } else if (main.x > 0) {
428 var action = getActionAt(Qt.point(mouse.x, mouse.y))447 var action = getActionAt(Qt.point(mouse.x, mouse.y))
429 if (action && action !== -1) {448 if (action && action !== -1) {
430449
=== modified file 'tests/autopilot/address_book_app/__init__.py'
--- tests/autopilot/address_book_app/__init__.py 2015-10-28 13:27:33 +0000
+++ tests/autopilot/address_book_app/__init__.py 2016-01-07 13:19:12 +0000
@@ -125,14 +125,13 @@
125 return None125 return None
126126
127 def click_action_button(self, action_name):127 def click_action_button(self, action_name):
128 actionbars = self.select_many('ActionBar', objectName='headerActionBar')128 actions = self.select_many(objectName='%s_button'%action_name)
129 for actionbar in actionbars:129 for action in actions:
130 try:130 if action.enabled:
131 actionbar.click_action_button(action_name)131 self.pointing_device.click_object(action)
132 return132 return
133 except ubuntuuitoolkit.ToolkitException:133
134 continue134 raise exceptions.StateNotFoundError(action_name)
135 raise exceptions.StateNotFoundError('Action %s not found.' % action_name)
136135
137 def open_header(self):136 def open_header(self):
138 header = self.get_header()137 header = self.get_header()
@@ -155,6 +154,25 @@
155154
156 return header155 return header
157156
157 def wait_bottom_edge(self, opened):
158 # wait bottom edge to fully appear
159 mainStack = self.wait_select_single(objectName='mainStack')
160 mainStack.bottomEdgeOpened.wait_for(opened)
161
162 def reveal_bottom_edge_page(self):
163 flickable = self.get_contact_list_view()
164
165 globalRect = flickable.globalRect
166 start_x = globalRect.x + (globalRect.width * 0.5)
167 start_y = globalRect.y + (flickable.height * 0.98)
168 stop_y = globalRect.y + (flickable.height * 0.4)
169
170 self.pointing_device.drag(
171 start_x, start_y, start_x, stop_y, rate=5)
172
173 # wait bottom edge to fully appear
174 self.wait_bottom_edge(True)
175
158 def cancel(self):176 def cancel(self):
159 """177 """
160 Press the 'Cancel' button178 Press the 'Cancel' button
@@ -165,6 +183,7 @@
165 self.pointing_device.click_object(button)183 self.pointing_device.click_object(button)
166 return184 return
167185
186 self.click_action_button('cancel')
168 #self.click_action_button("customBackButton")187 #self.click_action_button("customBackButton")
169188
170 def save(self):189 def save(self):
@@ -200,7 +219,6 @@
200 """219 """
201 Press the 'Add' button and return the contact editor page220 Press the 'Add' button and return the contact editor page
202 """221 """
203 bottom_swipe_page = self.get_contact_list_page()222 self.reveal_bottom_edge_page()
204 bottom_swipe_page.reveal_bottom_edge_page()
205223
206 return self.get_contact_edit_page()224 return self.get_contact_edit_page()
207225
=== modified file 'tests/autopilot/address_book_app/pages/_ab_contact_list_page.py'
--- tests/autopilot/address_book_app/pages/_ab_contact_list_page.py 2015-10-20 03:38:07 +0000
+++ tests/autopilot/address_book_app/pages/_ab_contact_list_page.py 2016-01-07 13:19:12 +0000
@@ -112,7 +112,7 @@
112 @log_action_info112 @log_action_info
113 def delete_selected_contacts(self, main_window):113 def delete_selected_contacts(self, main_window):
114 main_window.delete()114 main_window.delete()
115 self.bottomEdgePageOpened.wait_for(False)115 main_window.wait_bottom_edge(False)
116 dialog = self.get_root_instance().wait_select_single(116 dialog = self.get_root_instance().wait_select_single(
117 address_book.RemoveContactsDialog, objectName='removeContactsDialog')117 address_book.RemoveContactsDialog, objectName='removeContactsDialog')
118 dialog.confirm_removal()118 dialog.confirm_removal()
@@ -137,21 +137,3 @@
137 'ContactListButtonDelegate',137 'ContactListButtonDelegate',
138 objectName='contactListView.importFromSimCardButton')138 objectName='contactListView.importFromSimCardButton')
139 return import_from_sim_button.visible139 return import_from_sim_button.visible
140
141 def reveal_bottom_edge_page(self):
142 """Bring the bottom edge page to the screen"""
143 self.bottomEdgePageOpened.wait_for(False)
144 try:
145 action_item = self.wait_select_single(objectName='bottomEdgeDragArea')
146 action_item.enabled.wait_for(True)
147 start_x = (action_item.globalRect.x +
148 (action_item.globalRect.width * 0.5))
149 start_y = action_item.globalRect.y + (action_item.height * 0.2)
150 stop_y = start_y - (self.height * 0.7)
151 self.pointing_device.drag(
152 start_x, start_y, start_x, stop_y, rate=2)
153 #self pointer became invalid at this point
154 #self.bottomEdgePageOpened.wait_for(True)
155 except dbus.StateNotFoundError:
156 logger.error('ButtomEdge element not found.')
157 raise
158140
=== modified file 'tests/autopilot/address_book_app/tests/test_add_contact.py'
--- tests/autopilot/address_book_app/tests/test_add_contact.py 2015-10-20 03:38:07 +0000
+++ tests/autopilot/address_book_app/tests/test_add_contact.py 2016-01-07 13:19:12 +0000
@@ -36,8 +36,6 @@
36 contact_editor = self.app.main_window.go_to_add_contact()36 contact_editor = self.app.main_window.go_to_add_contact()
3737
38 # Check if the contact list disapear and contact editor appears38 # Check if the contact list disapear and contact editor appears
39 #FIXME: list_page became an invalid pointer after push a new page
40 #self.assertThat(list_page.bottomEdgePageOpened, Eventually(Equals(True)))
41 self.assertThat(contact_editor.visible, Eventually(Equals(True)))39 self.assertThat(contact_editor.visible, Eventually(Equals(True)))
42 self.assertThat(contact_editor.active, Eventually(Equals(True)))40 self.assertThat(contact_editor.active, Eventually(Equals(True)))
4341
@@ -46,7 +44,7 @@
4644
47 # Check if the contact list is visible again45 # Check if the contact list is visible again
48 self.assertThat(list_page.visible, Eventually(Equals(True)))46 self.assertThat(list_page.visible, Eventually(Equals(True)))
49 self.assertThat(list_page.bottomEdgePageOpened, Eventually(Equals(False)))47 self.app.main_window.wait_bottom_edge(False)
5048
51 # Check if the contact list still empty49 # Check if the contact list still empty
52 list_view = self.app.main_window.get_contact_list_view()50 list_view = self.app.main_window.get_contact_list_view()
5351
=== modified file 'tests/autopilot/address_book_app/tests/test_create_new_from_uri.py'
--- tests/autopilot/address_book_app/tests/test_create_new_from_uri.py 2015-10-20 03:38:07 +0000
+++ tests/autopilot/address_book_app/tests/test_create_new_from_uri.py 2016-01-07 13:19:12 +0000
@@ -23,8 +23,6 @@
2323
24 def test_save_new_contact(self):24 def test_save_new_contact(self):
25 list_page = self.app.main_window.get_contact_list_page()25 list_page = self.app.main_window.get_contact_list_page()
26 #FIXME: contacts list object became invalid after push a new page
27 #list_page.bottomEdgePageOpened.wait_for(True)
2826
29 edit_page = self.app.main_window.get_contact_edit_page()27 edit_page = self.app.main_window.get_contact_edit_page()
30 self.assertThat(edit_page.visible, Eventually(Equals(True)))28 self.assertThat(edit_page.visible, Eventually(Equals(True)))
3129
=== modified file 'tests/autopilot/address_book_app/tests/test_edit_contact.py'
--- tests/autopilot/address_book_app/tests/test_edit_contact.py 2015-10-20 03:38:07 +0000
+++ tests/autopilot/address_book_app/tests/test_edit_contact.py 2016-01-07 13:19:12 +0000
@@ -167,16 +167,14 @@
167 self.clear_text_on_field(last_name_field)167 self.clear_text_on_field(last_name_field)
168168
169 # check if is possible to save a contact without name169 # check if is possible to save a contact without name
170 self.app.main_window.save()170 self.assertThat(edit_page.saveActionEnabled, Eventually(Equals(False)))
171 accept_button = self.app.main_window.get_action("save")
172 self.assertThat(accept_button.enabled, Eventually(Equals(False)))
173171
174 # Cancel edit172 # Cancel edit
175 self.app.main_window.cancel()173 self.app.main_window.cancel()
176174
177 # Check if the names still there175 # Check if the names still there
178 view_page = self.app.main_window.get_contact_view_page()176 view_page = self.app.main_window.get_contact_view_page()
179 self.assertThat(view_page.title, Eventually(Equals("Fulano de Tal")))177 self.assertThat(view_page.headerTitle, Eventually(Equals("Fulano de Tal")))
180178
181 def test_im_type(self):179 def test_im_type(self):
182 contact_editor = self.app.main_window.go_to_add_contact()180 contact_editor = self.app.main_window.go_to_add_contact()
183181
=== modified file 'tests/autopilot/address_book_app/tests/test_import_vcard.py'
--- tests/autopilot/address_book_app/tests/test_import_vcard.py 2015-11-24 18:18:31 +0000
+++ tests/autopilot/address_book_app/tests/test_import_vcard.py 2016-01-07 13:19:12 +0000
@@ -30,7 +30,7 @@
30 # check if app enter on import state30 # check if app enter on import state
31 list_page = self.app.main_window.get_contact_list_page()31 list_page = self.app.main_window.get_contact_list_page()
32 self.assertThat(list_page.state, Eventually(Equals('vcardImported')))32 self.assertThat(list_page.state, Eventually(Equals('vcardImported')))
33 self.assertThat(list_page.title, Eventually(Equals('Imported contacts')))33 self.assertThat(list_page.headerTitle, Eventually(Equals('Imported contacts')))
34 self.assertThat(len(list_page.get_contacts()), Equals(3))34 self.assertThat(len(list_page.get_contacts()), Equals(3))
3535
36 #leave import state and show full contact list36 #leave import state and show full contact list
3737
=== modified file 'tests/autopilot/address_book_app/tests/test_single_pick_mode.py'
--- tests/autopilot/address_book_app/tests/test_single_pick_mode.py 2015-04-17 15:22:08 +0000
+++ tests/autopilot/address_book_app/tests/test_single_pick_mode.py 2016-01-07 13:19:12 +0000
@@ -32,6 +32,7 @@
32 if (contact.visible):32 if (contact.visible):
33 item = contact.select_single("QQuickRectangle",33 item = contact.select_single("QQuickRectangle",
34 objectName="mainItem")34 objectName="mainItem")
35 self.assertThat(contact.selected, Eventually(Equals(False)))
35 self.assertThat(item.color, Eventually(Equals(contact.color)))36 self.assertThat(item.color, Eventually(Equals(contact.color)))
36 selected_items.append(item)37 selected_items.append(item)
37 item_to_contacts[item] = contact38 item_to_contacts[item] = contact
3839
=== modified file 'tests/qml/tst_ContactPreviewPage.qml'
--- tests/qml/tst_ContactPreviewPage.qml 2015-11-16 15:44:43 +0000
+++ tests/qml/tst_ContactPreviewPage.qml 2016-01-07 13:19:12 +0000
@@ -104,13 +104,13 @@
104 function test_preview_contact_with_name()104 function test_preview_contact_with_name()
105 {105 {
106 contactPreviewPage.contact = createContactWithName()106 contactPreviewPage.contact = createContactWithName()
107 tryCompare(contactPreviewPage, "title", "Fulano")107 tryCompare(contactPreviewPage.header, "title", "Fulano")
108 }108 }
109109
110 function test_preview_contact_with_name_and_avatar()110 function test_preview_contact_with_name_and_avatar()
111 {111 {
112 contactPreviewPage.contact = createContactWithNameAndAvatar()112 contactPreviewPage.contact = createContactWithNameAndAvatar()
113 tryCompare(contactPreviewPage, "title", "Fulano")113 tryCompare(contactPreviewPage.header, "title", "Fulano")
114 var avatarField = findChild(root, "contactAvatarDetail")114 var avatarField = findChild(root, "contactAvatarDetail")
115 tryCompare(avatarField, "avatarUrl", "image://theme/address-book-app")115 tryCompare(avatarField, "avatarUrl", "image://theme/address-book-app")
116 }116 }
@@ -120,7 +120,7 @@
120 compare(vcardParser.contacts.length, 1)120 compare(vcardParser.contacts.length, 1)
121 var contact = vcardParser.contacts[0]121 var contact = vcardParser.contacts[0]
122 contactPreviewPage.contact = contact122 contactPreviewPage.contact = contact
123 tryCompare(contactPreviewPage, "title", "Forrest Gump")123 tryCompare(contactPreviewPage.header, "title", "Forrest Gump")
124 // PhoneNumbers124 // PhoneNumbers
125 // TEL;TYPE=WORK,VOICE:(111) 555-12121125 // TEL;TYPE=WORK,VOICE:(111) 555-12121
126 // TEL;TYPE=HOME,VOICE:(404) 555-1212126 // TEL;TYPE=HOME,VOICE:(404) 555-1212
@@ -263,8 +263,7 @@
263 compare(vcardParser.contacts.length, 1)263 compare(vcardParser.contacts.length, 1)
264 var contact = vcardParser.contacts[0]264 var contact = vcardParser.contacts[0]
265 contactPreviewPage.contact = contact265 contactPreviewPage.contact = contact
266 tryCompare(contactPreviewPage, "title", "Forrest Gump")266 tryCompare(contactPreviewPage.header, "title", "Forrest Gump")
267
268267
269 // page is enabled by default268 // page is enabled by default
270 var avatar = findChild(contactPreviewPage, "avatar")269 var avatar = findChild(contactPreviewPage, "avatar")

Subscribers

People subscribed via source and target branches