aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGriffin Millender <griffinn.millender@gmail.com>2015-06-01 08:54:24 -0400
committerGriffin Millender <griffinn.millender@gmail.com>2015-06-12 03:35:49 -0500
commit8d769985a59484a0a2be38a8c4ad1a2824e04eae (patch)
treee4b7a1a5bd6bfb55344eb81f07a88be274d3ce03
parenta03a4546fe42c66ccca3f9813babcbf9869750a5 (diff)
Update cards lib
squashed all changes from: https://github.com/gabrielemariotti/cardslib Thanks a bunch to gabrielemariotti for the cardslib Change-Id: I96922b3ca76a7b89af7fce039eb33f499790f0a0
-rw-r--r--res/drawable-hdpi/ic_chevron_right_grey600_24dp.pngbin0 -> 271 bytes
-rw-r--r--res/drawable-hdpi/ic_expand_less_black_24dp.pngbin0 -> 234 bytes
-rw-r--r--res/drawable-hdpi/ic_expand_less_grey600_24dp.pngbin0 -> 280 bytes
-rw-r--r--res/drawable-hdpi/ic_expand_more_black_24dp.pngbin0 -> 244 bytes
-rw-r--r--res/drawable-hdpi/ic_expand_more_grey600_24dp.pngbin0 -> 291 bytes
-rw-r--r--res/drawable-hdpi/ic_menu_expand_card_dark_normal.pngbin554 -> 1135 bytes
-rw-r--r--res/drawable-hdpi/ic_menu_expand_card_dark_pressed.pngbin481 -> 22602 bytes
-rw-r--r--res/drawable-hdpi/ic_more_vert_black_24dp.pngbin0 -> 214 bytes
-rw-r--r--res/drawable-hdpi/ic_more_vert_grey600_24dp.pngbin0 -> 221 bytes
-rw-r--r--res/drawable-mdpi/ic_chevron_right_grey600_24dp.pngbin0 -> 225 bytes
-rw-r--r--res/drawable-mdpi/ic_expand_less_black_24dp.pngbin0 -> 206 bytes
-rw-r--r--res/drawable-mdpi/ic_expand_less_grey600_24dp.pngbin0 -> 240 bytes
-rw-r--r--res/drawable-mdpi/ic_expand_more_black_24dp.pngbin0 -> 206 bytes
-rw-r--r--res/drawable-mdpi/ic_expand_more_grey600_24dp.pngbin0 -> 222 bytes
-rw-r--r--res/drawable-mdpi/ic_menu_expand_card_dark_normal.pngbin412 -> 679 bytes
-rw-r--r--res/drawable-mdpi/ic_menu_expand_card_dark_pressed.pngbin348 -> 21985 bytes
-rw-r--r--res/drawable-mdpi/ic_more_vert_black_24dp.pngbin0 -> 189 bytes
-rw-r--r--res/drawable-mdpi/ic_more_vert_grey600_24dp.pngbin0 -> 202 bytes
-rw-r--r--res/drawable-v21/card_foreground_kitkat_selector.xml34
-rw-r--r--res/drawable-v21/card_foreground_selector.xml35
-rw-r--r--res/drawable-v21/card_kitkat_selector.xml35
-rw-r--r--res/drawable-v21/card_menu_button_expand.xml32
-rw-r--r--res/drawable-v21/card_menu_button_expand_material.xml33
-rw-r--r--res/drawable-v21/card_menu_button_expand_material_animator.xml46
-rw-r--r--res/drawable-v21/card_menu_button_overflow_material.xml42
-rw-r--r--res/drawable-v21/card_selector.xml32
-rw-r--r--res/drawable-xhdpi/ic_chevron_right_grey600_24dp.pngbin0 -> 305 bytes
-rw-r--r--res/drawable-xhdpi/ic_expand_less_black_24dp.pngbin0 -> 259 bytes
-rw-r--r--res/drawable-xhdpi/ic_expand_less_grey600_24dp.pngbin0 -> 311 bytes
-rw-r--r--res/drawable-xhdpi/ic_expand_more_black_24dp.pngbin0 -> 272 bytes
-rw-r--r--res/drawable-xhdpi/ic_expand_more_black_36dp.pngbin0 -> 316 bytes
-rw-r--r--res/drawable-xhdpi/ic_expand_more_grey600_24dp.pngbin0 -> 324 bytes
-rw-r--r--res/drawable-xhdpi/ic_expand_more_grey600_36dp.pngbin0 -> 411 bytes
-rw-r--r--res/drawable-xhdpi/ic_menu_expand_card_dark_normal.pngbin828 -> 1458 bytes
-rw-r--r--res/drawable-xhdpi/ic_menu_expand_card_dark_pressed.pngbin738 -> 23419 bytes
-rw-r--r--res/drawable-xhdpi/ic_more_vert_black_36dp.pngbin0 -> 296 bytes
-rw-r--r--res/drawable-xhdpi/ic_more_vert_grey600_36dp.pngbin0 -> 316 bytes
-rw-r--r--res/drawable-xxhdpi/ic_chevron_right_grey600_24dp.pngbin0 -> 388 bytes
-rw-r--r--res/drawable-xxhdpi/ic_expand_less_black_24dp.pngbin0 -> 304 bytes
-rw-r--r--res/drawable-xxhdpi/ic_expand_less_grey600_24dp.pngbin0 -> 392 bytes
-rw-r--r--res/drawable-xxhdpi/ic_expand_more_black_18dp.pngbin0 -> 277 bytes
-rw-r--r--res/drawable-xxhdpi/ic_expand_more_black_24dp.pngbin0 -> 316 bytes
-rw-r--r--res/drawable-xxhdpi/ic_expand_more_grey600_18dp.pngbin0 -> 348 bytes
-rw-r--r--res/drawable-xxhdpi/ic_expand_more_grey600_24dp.pngbin0 -> 411 bytes
-rw-r--r--res/drawable-xxhdpi/ic_menu_expand_card_dark_normal.pngbin1104 -> 2187 bytes
-rw-r--r--res/drawable-xxhdpi/ic_menu_expand_card_dark_pressed.pngbin961 -> 24342 bytes
-rw-r--r--res/drawable-xxhdpi/ic_menu_overflow_card.pngbin0 -> 21713 bytes
-rw-r--r--res/drawable-xxhdpi/ic_more_vert_black_18dp.pngbin0 -> 252 bytes
-rw-r--r--res/drawable-xxhdpi/ic_more_vert_black_24dp.pngbin0 -> 296 bytes
-rw-r--r--res/drawable-xxhdpi/ic_more_vert_grey600_18dp.pngbin0 -> 263 bytes
-rw-r--r--res/drawable-xxhdpi/ic_more_vert_grey600_24dp.pngbin0 -> 316 bytes
-rw-r--r--res/drawable-xxxhdpi/ic_chevron_right_grey600_24dp.pngbin0 -> 472 bytes
-rw-r--r--res/drawable-xxxhdpi/ic_expand_less_black_24dp.pngbin0 -> 360 bytes
-rw-r--r--res/drawable-xxxhdpi/ic_expand_less_grey600_24dp.pngbin0 -> 474 bytes
-rw-r--r--res/drawable-xxxhdpi/ic_expand_more_black_24dp.pngbin0 -> 379 bytes
-rw-r--r--res/drawable-xxxhdpi/ic_expand_more_grey600_24dp.pngbin0 -> 507 bytes
-rw-r--r--res/drawable-xxxhdpi/ic_more_vert_black_24dp.pngbin0 -> 393 bytes
-rw-r--r--res/drawable-xxxhdpi/ic_more_vert_grey600_24dp.pngbin0 -> 403 bytes
-rw-r--r--res/drawable/activated_foreground_card.xml25
-rw-r--r--res/drawable/activated_foreground_kitkat_card.xml25
-rw-r--r--res/drawable/card_foreground_kitkat_selector.xml4
-rw-r--r--res/drawable/card_foreground_selector.xml4
-rw-r--r--res/drawable/card_menu_button_expand_material.xml30
-rw-r--r--res/drawable/card_menu_button_expand_material_animator.xml30
-rw-r--r--res/drawable/card_menu_button_overflow_material.xml30
-rw-r--r--res/drawable/card_menu_button_rounded_overflow_selector.xml30
-rw-r--r--res/drawable/native_card_selector.xml28
-rw-r--r--res/layout/base_header_layout.xml4
-rw-r--r--res/layout/base_list_expandable_children_layout.xml40
-rw-r--r--res/layout/base_section_layout.xml31
-rw-r--r--res/layout/base_withlist_empty.xml32
-rw-r--r--res/layout/base_withlist_progress.xml42
-rw-r--r--res/layout/card_base_layout.xml2
-rw-r--r--res/layout/card_layout.xml2
-rw-r--r--res/layout/card_overlay_layout.xml2
-rw-r--r--res/layout/card_thumbnail_layout.xml2
-rw-r--r--res/layout/card_thumbnail_overlay_layout.xml2
-rw-r--r--res/layout/inner_base_expand.xml2
-rw-r--r--res/layout/inner_base_header.xml6
-rw-r--r--res/layout/inner_base_main.xml6
-rw-r--r--res/layout/inner_base_main_cardwithlist.xml57
-rw-r--r--res/layout/list_card_undo_material_message.xml38
-rw-r--r--res/layout/list_card_undo_materialmobile_message.xml38
-rw-r--r--res/layout/native_base_header_layout.xml71
-rw-r--r--res/layout/native_base_thumbnail_layout.xml25
-rw-r--r--res/layout/native_card_layout.xml66
-rw-r--r--res/layout/native_card_thumbnail_layout.xml79
-rw-r--r--res/layout/native_cardwithlist_layout.xml65
-rw-r--r--res/layout/native_inner_base_expand.xml34
-rw-r--r--res/layout/native_inner_base_header.xml38
-rw-r--r--res/layout/native_inner_base_main.xml36
-rw-r--r--res/layout/native_inner_base_main_cardwithlist.xml57
-rw-r--r--res/layout/native_list_card_layout.xml36
-rw-r--r--res/layout/native_list_card_thumbnail_layout.xml38
-rw-r--r--res/values-de/strings.xml41
-rw-r--r--res/values-v16/fonts.xml29
-rw-r--r--res/values-v16/styles.xml99
-rw-r--r--res/values-v21/fonts.xml26
-rw-r--r--res/values-v21/styles.xml73
-rw-r--r--res/values/attrs.xml8
-rw-r--r--res/values/colors.xml18
-rw-r--r--res/values/colors_undo.xml23
-rw-r--r--res/values/dimens.xml130
-rw-r--r--res/values/fonts.xml23
-rw-r--r--res/values/integers.xml22
-rw-r--r--res/values/strings.xml6
-rw-r--r--res/values/styles.xml299
-rw-r--r--res/values/styles_undo.xml102
-rw-r--r--src/com/android/cards/internal/overflowanimation/BaseCardOverlayAnimation.java175
-rw-r--r--src/com/android/cards/internal/overflowanimation/BaseOverflowAnimation.java168
-rw-r--r--src/com/android/cards/internal/overflowanimation/TwoCardOverlayAnimation.java242
-rw-r--r--src/com/android/cards/view/listener/UndoBarController.java240
-rw-r--r--src/it/gmariotti/cardslib/library/Constants.java (renamed from src/com/android/cards/Constants.java)4
-rw-r--r--src/it/gmariotti/cardslib/library/internal/BaseGroupExpandableCard.java47
-rw-r--r--src/it/gmariotti/cardslib/library/internal/Card.java (renamed from src/com/android/cards/internal/Card.java)318
-rw-r--r--src/it/gmariotti/cardslib/library/internal/CardArrayAdapter.java (renamed from src/com/android/cards/internal/CardArrayAdapter.java)268
-rw-r--r--src/it/gmariotti/cardslib/library/internal/CardArrayMultiChoiceAdapter.java (renamed from src/com/android/cards/internal/CardArrayMultiChoiceAdapter.java)5
-rw-r--r--src/it/gmariotti/cardslib/library/internal/CardCursorAdapter.java (renamed from src/com/android/cards/internal/CardCursorAdapter.java)31
-rw-r--r--src/it/gmariotti/cardslib/library/internal/CardCursorMultiChoiceAdapter.java162
-rw-r--r--src/it/gmariotti/cardslib/library/internal/CardExpand.java (renamed from src/com/android/cards/internal/CardExpand.java)39
-rw-r--r--src/it/gmariotti/cardslib/library/internal/CardExpandableListAdapter.java220
-rw-r--r--src/it/gmariotti/cardslib/library/internal/CardGridArrayAdapter.java (renamed from src/com/android/cards/internal/CardGridArrayAdapter.java)30
-rw-r--r--src/it/gmariotti/cardslib/library/internal/CardGridArrayMultiChoiceAdapter.java (renamed from src/com/android/cards/internal/CardGridArrayMultiChoiceAdapter.java)5
-rw-r--r--src/it/gmariotti/cardslib/library/internal/CardGridCursorAdapter.java (renamed from src/com/android/cards/internal/CardGridCursorAdapter.java)25
-rw-r--r--src/it/gmariotti/cardslib/library/internal/CardHeader.java (renamed from src/com/android/cards/internal/CardHeader.java)63
-rw-r--r--src/it/gmariotti/cardslib/library/internal/CardThumbnail.java (renamed from src/com/android/cards/internal/CardThumbnail.java)0
-rw-r--r--src/it/gmariotti/cardslib/library/internal/ViewToClickToExpand.java (renamed from src/com/android/cards/internal/ViewToClickToExpand.java)49
-rw-r--r--src/it/gmariotti/cardslib/library/internal/base/BaseCard.java (renamed from src/com/android/cards/internal/base/BaseCard.java)14
-rw-r--r--src/it/gmariotti/cardslib/library/internal/base/BaseCardArrayAdapter.java (renamed from src/com/android/cards/internal/base/BaseCardArrayAdapter.java)4
-rw-r--r--src/it/gmariotti/cardslib/library/internal/base/BaseCardCursorAdapter.java (renamed from src/com/android/cards/internal/base/BaseCardCursorAdapter.java)11
-rw-r--r--src/it/gmariotti/cardslib/library/internal/base/CardUIInferface.java (renamed from src/com/android/cards/internal/base/CardUIInterface.java)2
-rw-r--r--src/it/gmariotti/cardslib/library/internal/dismissanimation/BaseDismissAnimation.java (renamed from src/com/android/cards/internal/dismissanimation/BaseDismissAnimation.java)28
-rw-r--r--src/it/gmariotti/cardslib/library/internal/dismissanimation/SwipeDismissAnimation.java (renamed from src/com/android/cards/internal/dismissanimation/SwipeDismissAnimation.java)9
-rw-r--r--src/it/gmariotti/cardslib/library/internal/multichoice/DefaultOptionMultiChoice.java (renamed from src/com/android/cards/internal/multichoice/DefaultOptionMultiChoice.java)0
-rw-r--r--src/it/gmariotti/cardslib/library/internal/multichoice/MultiChoiceAdapter.java (renamed from src/com/android/cards/internal/multichoice/MultiChoiceAdapter.java)7
-rw-r--r--src/it/gmariotti/cardslib/library/internal/multichoice/MultiChoiceAdapterHelperBase.java (renamed from src/com/android/cards/internal/multichoice/MultiChoiceAdapterHelperBase.java)8
-rw-r--r--src/it/gmariotti/cardslib/library/internal/multichoice/OptionMultiChoice.java (renamed from src/com/android/cards/internal/multichoice/OptionMultiChoice.java)0
-rw-r--r--src/it/gmariotti/cardslib/library/prototypes/CardSection.java47
-rw-r--r--src/it/gmariotti/cardslib/library/prototypes/CardWithList.java1027
-rw-r--r--src/it/gmariotti/cardslib/library/prototypes/LinearListView.java383
-rw-r--r--src/it/gmariotti/cardslib/library/prototypes/SectionedCardAdapter.java346
-rw-r--r--src/it/gmariotti/cardslib/library/prototypes/SwipeDismissListItemViewTouchListener.java289
-rw-r--r--src/it/gmariotti/cardslib/library/utils/BitmapUtils.java (renamed from src/com/android/cards/utils/BitmapUtils.java)0
-rw-r--r--src/it/gmariotti/cardslib/library/utils/CacheUtil.java (renamed from src/com/android/cards/utils/CacheUtil.java)0
-rw-r--r--src/it/gmariotti/cardslib/library/view/BaseCardView.java (renamed from src/com/android/cards/view/BaseCardView.java)12
-rw-r--r--src/it/gmariotti/cardslib/library/view/CardExpandableListView.java149
-rw-r--r--src/it/gmariotti/cardslib/library/view/CardGridView.java (renamed from src/com/android/cards/view/CardGridView.java)7
-rw-r--r--src/it/gmariotti/cardslib/library/view/CardListView.java (renamed from src/com/android/cards/view/CardListView.java)45
-rw-r--r--src/it/gmariotti/cardslib/library/view/CardView.java (renamed from src/com/android/cards/view/CardView.java)491
-rw-r--r--src/it/gmariotti/cardslib/library/view/CardViewNative.java1271
-rw-r--r--src/it/gmariotti/cardslib/library/view/ForegroundLinearLayout.java (renamed from src/com/android/cards/view/ForegroundLinearLayout.java)16
-rw-r--r--src/it/gmariotti/cardslib/library/view/base/CardViewInterface.java (renamed from src/com/android/cards/view/base/CardViewInterface.java)0
-rw-r--r--src/it/gmariotti/cardslib/library/view/base/CardViewWrapper.java162
-rw-r--r--src/it/gmariotti/cardslib/library/view/component/CardHeaderView.java (renamed from src/com/android/cards/view/component/CardHeaderView.java)76
-rw-r--r--src/it/gmariotti/cardslib/library/view/component/CardShadowView.java (renamed from src/com/android/cards/view/component/CardShadowView.java)0
-rw-r--r--src/it/gmariotti/cardslib/library/view/component/CardThumbnailView.java (renamed from src/com/android/cards/view/component/CardThumbnailView.java)74
-rw-r--r--src/it/gmariotti/cardslib/library/view/helper/CardViewHelper.java54
-rw-r--r--src/it/gmariotti/cardslib/library/view/helper/CardViewHelperImplBase.java82
-rw-r--r--src/it/gmariotti/cardslib/library/view/helper/CardViewHelperImplJB.java49
-rw-r--r--src/it/gmariotti/cardslib/library/view/helper/CardViewHelperImplKK.java36
-rw-r--r--src/it/gmariotti/cardslib/library/view/helper/CardViewHelperImplL.java49
-rw-r--r--src/it/gmariotti/cardslib/library/view/helper/CardViewHelperUtil.java44
-rw-r--r--src/it/gmariotti/cardslib/library/view/listener/SwipeDismissListViewTouchListener.java (renamed from src/com/android/cards/view/listener/SwipeDismissListViewTouchListener.java)174
-rw-r--r--src/it/gmariotti/cardslib/library/view/listener/SwipeDismissTopBottomTouchListener.java285
-rw-r--r--src/it/gmariotti/cardslib/library/view/listener/SwipeDismissTouchListener.java284
-rw-r--r--src/it/gmariotti/cardslib/library/view/listener/SwipeDismissViewTouchListener.java (renamed from src/com/android/cards/view/listener/SwipeDismissViewTouchListener.java)78
-rw-r--r--src/it/gmariotti/cardslib/library/view/listener/SwipeOnScrollListener.java (renamed from src/com/android/cards/view/listener/SwipeOnScrollListener.java)2
-rw-r--r--src/it/gmariotti/cardslib/library/view/listener/UndoBarController.java478
-rw-r--r--src/it/gmariotti/cardslib/library/view/listener/UndoCard.java (renamed from src/com/android/cards/view/listener/UndoCard.java)0
-rw-r--r--src/it/gmariotti/cardslib/library/view/listener/dismiss/AbstractDismissableManager.java44
-rw-r--r--src/it/gmariotti/cardslib/library/view/listener/dismiss/DefaultDismissableManager.java35
-rw-r--r--src/it/gmariotti/cardslib/library/view/listener/dismiss/Dismissable.java59
172 files changed, 8887 insertions, 1680 deletions
diff --git a/res/drawable-hdpi/ic_chevron_right_grey600_24dp.png b/res/drawable-hdpi/ic_chevron_right_grey600_24dp.png
new file mode 100644
index 0000000..7eef500
--- /dev/null
+++ b/res/drawable-hdpi/ic_chevron_right_grey600_24dp.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_expand_less_black_24dp.png b/res/drawable-hdpi/ic_expand_less_black_24dp.png
new file mode 100644
index 0000000..35e3b42
--- /dev/null
+++ b/res/drawable-hdpi/ic_expand_less_black_24dp.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_expand_less_grey600_24dp.png b/res/drawable-hdpi/ic_expand_less_grey600_24dp.png
new file mode 100644
index 0000000..96758c8
--- /dev/null
+++ b/res/drawable-hdpi/ic_expand_less_grey600_24dp.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_expand_more_black_24dp.png b/res/drawable-hdpi/ic_expand_more_black_24dp.png
new file mode 100644
index 0000000..ed993f3
--- /dev/null
+++ b/res/drawable-hdpi/ic_expand_more_black_24dp.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_expand_more_grey600_24dp.png b/res/drawable-hdpi/ic_expand_more_grey600_24dp.png
new file mode 100644
index 0000000..00b9f64
--- /dev/null
+++ b/res/drawable-hdpi/ic_expand_more_grey600_24dp.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_expand_card_dark_normal.png b/res/drawable-hdpi/ic_menu_expand_card_dark_normal.png
index c691aeb..c5a494c 100644
--- a/res/drawable-hdpi/ic_menu_expand_card_dark_normal.png
+++ b/res/drawable-hdpi/ic_menu_expand_card_dark_normal.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_expand_card_dark_pressed.png b/res/drawable-hdpi/ic_menu_expand_card_dark_pressed.png
index 584d599..3d0a792 100644
--- a/res/drawable-hdpi/ic_menu_expand_card_dark_pressed.png
+++ b/res/drawable-hdpi/ic_menu_expand_card_dark_pressed.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_more_vert_black_24dp.png b/res/drawable-hdpi/ic_more_vert_black_24dp.png
new file mode 100644
index 0000000..f22e713
--- /dev/null
+++ b/res/drawable-hdpi/ic_more_vert_black_24dp.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_more_vert_grey600_24dp.png b/res/drawable-hdpi/ic_more_vert_grey600_24dp.png
new file mode 100644
index 0000000..e141502
--- /dev/null
+++ b/res/drawable-hdpi/ic_more_vert_grey600_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_chevron_right_grey600_24dp.png b/res/drawable-mdpi/ic_chevron_right_grey600_24dp.png
new file mode 100644
index 0000000..d6581fe
--- /dev/null
+++ b/res/drawable-mdpi/ic_chevron_right_grey600_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_expand_less_black_24dp.png b/res/drawable-mdpi/ic_expand_less_black_24dp.png
new file mode 100644
index 0000000..a5ab2c5
--- /dev/null
+++ b/res/drawable-mdpi/ic_expand_less_black_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_expand_less_grey600_24dp.png b/res/drawable-mdpi/ic_expand_less_grey600_24dp.png
new file mode 100644
index 0000000..d83b2e1
--- /dev/null
+++ b/res/drawable-mdpi/ic_expand_less_grey600_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_expand_more_black_24dp.png b/res/drawable-mdpi/ic_expand_more_black_24dp.png
new file mode 100644
index 0000000..73fc3b4
--- /dev/null
+++ b/res/drawable-mdpi/ic_expand_more_black_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_expand_more_grey600_24dp.png b/res/drawable-mdpi/ic_expand_more_grey600_24dp.png
new file mode 100644
index 0000000..b2c6b76
--- /dev/null
+++ b/res/drawable-mdpi/ic_expand_more_grey600_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_expand_card_dark_normal.png b/res/drawable-mdpi/ic_menu_expand_card_dark_normal.png
index fe1c3e5..4cfa220 100644
--- a/res/drawable-mdpi/ic_menu_expand_card_dark_normal.png
+++ b/res/drawable-mdpi/ic_menu_expand_card_dark_normal.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_expand_card_dark_pressed.png b/res/drawable-mdpi/ic_menu_expand_card_dark_pressed.png
index 2cafbd1..60136bf 100644
--- a/res/drawable-mdpi/ic_menu_expand_card_dark_pressed.png
+++ b/res/drawable-mdpi/ic_menu_expand_card_dark_pressed.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_more_vert_black_24dp.png b/res/drawable-mdpi/ic_more_vert_black_24dp.png
new file mode 100644
index 0000000..991ad6c
--- /dev/null
+++ b/res/drawable-mdpi/ic_more_vert_black_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_more_vert_grey600_24dp.png b/res/drawable-mdpi/ic_more_vert_grey600_24dp.png
new file mode 100644
index 0000000..4ed3435
--- /dev/null
+++ b/res/drawable-mdpi/ic_more_vert_grey600_24dp.png
Binary files differ
diff --git a/res/drawable-v21/card_foreground_kitkat_selector.xml b/res/drawable-v21/card_foreground_kitkat_selector.xml
new file mode 100644
index 0000000..068560f
--- /dev/null
+++ b/res/drawable-v21/card_foreground_kitkat_selector.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:attr/colorControlHighlight">
+ <item android:drawable="@android:color/transparent"/>
+ <item>
+ <selector
+ android:exitFadeDuration="@android:integer/config_mediumAnimTime">
+ <item
+ android:state_activated="true"
+ android:drawable="@drawable/activated_foreground_kitkat_card"/>
+
+ <item android:drawable="@android:color/transparent"/>
+ </selector>
+ </item>
+</ripple>
diff --git a/res/drawable-v21/card_foreground_selector.xml b/res/drawable-v21/card_foreground_selector.xml
new file mode 100644
index 0000000..e976af2
--- /dev/null
+++ b/res/drawable-v21/card_foreground_selector.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:attr/colorControlHighlight">
+ <item android:drawable="@android:color/transparent"/>
+ <item>
+ <selector
+ android:exitFadeDuration="@android:integer/config_mediumAnimTime">
+
+ <item
+ android:state_activated="true"
+ android:drawable="@drawable/activated_foreground_card"/>
+
+ <item android:drawable="@android:color/transparent"/>
+ </selector>
+ </item>
+</ripple>
diff --git a/res/drawable-v21/card_kitkat_selector.xml b/res/drawable-v21/card_kitkat_selector.xml
new file mode 100644
index 0000000..b8b47f0
--- /dev/null
+++ b/res/drawable-v21/card_kitkat_selector.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:attr/colorControlHighlight">
+ <item android:drawable="@android:color/transparent"/>
+ <item>
+ <selector
+ android:exitFadeDuration="@android:integer/config_mediumAnimTime">
+
+ <item
+ android:state_activated="true"
+ android:drawable="@drawable/activated_background_kitkat_card"/>
+
+ <item android:drawable="@drawable/card_background"/>
+ </selector>
+ </item>
+</ripple> \ No newline at end of file
diff --git a/res/drawable-v21/card_menu_button_expand.xml b/res/drawable-v21/card_menu_button_expand.xml
new file mode 100644
index 0000000..ff2b0bc
--- /dev/null
+++ b/res/drawable-v21/card_menu_button_expand.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item
+ android:state_focused="true"
+ android:drawable="@drawable/ic_menu_expand_card_dark_pressed" />
+ <item
+ android:drawable="@drawable/ic_menu_expand_card_dark_pressed"
+ android:state_selected="true">
+
+ </item>
+ <item android:drawable="@drawable/ic_menu_expand_card_dark_normal"/>
+
+</selector> \ No newline at end of file
diff --git a/res/drawable-v21/card_menu_button_expand_material.xml b/res/drawable-v21/card_menu_button_expand_material.xml
new file mode 100644
index 0000000..310a320
--- /dev/null
+++ b/res/drawable-v21/card_menu_button_expand_material.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item
+ android:state_focused="true"
+ android:drawable="@drawable/ic_expand_more_black_24dp" />
+ <item
+ android:drawable="@drawable/ic_expand_more_black_24dp"
+ android:state_selected="true">
+
+ </item>
+ <item android:drawable="@drawable/ic_expand_more_grey600_24dp"/>
+
+</selector> \ No newline at end of file
diff --git a/res/drawable-v21/card_menu_button_expand_material_animator.xml b/res/drawable-v21/card_menu_button_expand_material_animator.xml
new file mode 100644
index 0000000..1390e5b
--- /dev/null
+++ b/res/drawable-v21/card_menu_button_expand_material_animator.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+<!-- res/drawable/myanimstatedrawable.xml -->
+<animated-selector
+ xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <!-- provide a different drawable for each state-->
+ <item android:id="@+id/pressed" android:drawable="@drawable/ic_expand_less_black_24dp"
+ android:state_pressed="true"/>
+ <item android:id="@+id/selected" android:drawable="@drawable/ic_expand_less_black_24dp"
+ android:state_selected="true"/>
+ <item android:id="@+id/normal"
+ android:drawable="@drawable/ic_expand_more_grey600_24dp"/>
+
+ <!-- specify a transition -->
+ <transition android:fromId="@+id/normal" android:toId="@+id/selected">
+ <animation-list>
+ <item android:duration="15" android:drawable="@drawable/ic_chevron_right_grey600_24dp"/>
+ <item android:duration="15" android:drawable="@drawable/ic_expand_less_grey600_24dp"/>
+ </animation-list>
+ </transition>
+
+ <transition android:fromId="@+id/selected" android:toId="@+id/normal">
+ <animation-list>
+ <item android:duration="15" android:drawable="@drawable/ic_expand_less_grey600_24dp"/>
+ <item android:duration="15" android:drawable="@drawable/ic_chevron_right_grey600_24dp"/>
+ </animation-list>
+ </transition>
+
+</animated-selector> \ No newline at end of file
diff --git a/res/drawable-v21/card_menu_button_overflow_material.xml b/res/drawable-v21/card_menu_button_overflow_material.xml
new file mode 100644
index 0000000..c37241d
--- /dev/null
+++ b/res/drawable-v21/card_menu_button_overflow_material.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item
+ android:drawable="@drawable/ic_more_vert_black_24dp"
+ android:state_focused="true"/>
+ <item
+ android:drawable="@drawable/ic_more_vert_black_24dp"
+ android:state_selected="true"/>
+
+ <item android:state_pressed="true">
+ <ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:attr/colorControlHighlight">
+ <item android:id="@android:id/mask">
+ <shape android:shape="oval" android:innerRadius="40dp"/>
+ </item>
+ <item android:drawable="@drawable/ic_more_vert_black_24dp"/>
+ </ripple>
+ </item>
+
+ <item android:drawable="@drawable/ic_more_vert_grey600_24dp"/>
+
+</selector>
diff --git a/res/drawable-v21/card_selector.xml b/res/drawable-v21/card_selector.xml
new file mode 100644
index 0000000..10e15a3
--- /dev/null
+++ b/res/drawable-v21/card_selector.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:attr/colorControlHighlight">
+ <item android:drawable="@android:color/transparent"/>
+ <item>
+ <selector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:exitFadeDuration="@android:integer/config_mediumAnimTime">
+ <item
+ android:state_activated="true"
+ android:drawable="@drawable/activated_background_card"/>
+ <item android:drawable="@drawable/card_background"/>
+ </selector>
+ </item>
+</ripple> \ No newline at end of file
diff --git a/res/drawable-xhdpi/ic_chevron_right_grey600_24dp.png b/res/drawable-xhdpi/ic_chevron_right_grey600_24dp.png
new file mode 100644
index 0000000..7b82b8a
--- /dev/null
+++ b/res/drawable-xhdpi/ic_chevron_right_grey600_24dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_expand_less_black_24dp.png b/res/drawable-xhdpi/ic_expand_less_black_24dp.png
new file mode 100644
index 0000000..47c7b52
--- /dev/null
+++ b/res/drawable-xhdpi/ic_expand_less_black_24dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_expand_less_grey600_24dp.png b/res/drawable-xhdpi/ic_expand_less_grey600_24dp.png
new file mode 100644
index 0000000..f117dc6
--- /dev/null
+++ b/res/drawable-xhdpi/ic_expand_less_grey600_24dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_expand_more_black_24dp.png b/res/drawable-xhdpi/ic_expand_more_black_24dp.png
new file mode 100644
index 0000000..45d30d9
--- /dev/null
+++ b/res/drawable-xhdpi/ic_expand_more_black_24dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_expand_more_black_36dp.png b/res/drawable-xhdpi/ic_expand_more_black_36dp.png
new file mode 100644
index 0000000..aadd04a
--- /dev/null
+++ b/res/drawable-xhdpi/ic_expand_more_black_36dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_expand_more_grey600_24dp.png b/res/drawable-xhdpi/ic_expand_more_grey600_24dp.png
new file mode 100644
index 0000000..8702c9a
--- /dev/null
+++ b/res/drawable-xhdpi/ic_expand_more_grey600_24dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_expand_more_grey600_36dp.png b/res/drawable-xhdpi/ic_expand_more_grey600_36dp.png
new file mode 100644
index 0000000..921249f
--- /dev/null
+++ b/res/drawable-xhdpi/ic_expand_more_grey600_36dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_expand_card_dark_normal.png b/res/drawable-xhdpi/ic_menu_expand_card_dark_normal.png
index b681a23..5947996 100644
--- a/res/drawable-xhdpi/ic_menu_expand_card_dark_normal.png
+++ b/res/drawable-xhdpi/ic_menu_expand_card_dark_normal.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_expand_card_dark_pressed.png b/res/drawable-xhdpi/ic_menu_expand_card_dark_pressed.png
index 7b27084..1abc4e7 100644
--- a/res/drawable-xhdpi/ic_menu_expand_card_dark_pressed.png
+++ b/res/drawable-xhdpi/ic_menu_expand_card_dark_pressed.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_more_vert_black_36dp.png b/res/drawable-xhdpi/ic_more_vert_black_36dp.png
new file mode 100644
index 0000000..d32453d
--- /dev/null
+++ b/res/drawable-xhdpi/ic_more_vert_black_36dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_more_vert_grey600_36dp.png b/res/drawable-xhdpi/ic_more_vert_grey600_36dp.png
new file mode 100644
index 0000000..44012b8
--- /dev/null
+++ b/res/drawable-xhdpi/ic_more_vert_grey600_36dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_chevron_right_grey600_24dp.png b/res/drawable-xxhdpi/ic_chevron_right_grey600_24dp.png
new file mode 100644
index 0000000..360d3c5
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_chevron_right_grey600_24dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_expand_less_black_24dp.png b/res/drawable-xxhdpi/ic_expand_less_black_24dp.png
new file mode 100644
index 0000000..0470e3f
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_expand_less_black_24dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_expand_less_grey600_24dp.png b/res/drawable-xxhdpi/ic_expand_less_grey600_24dp.png
new file mode 100644
index 0000000..63b7299
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_expand_less_grey600_24dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_expand_more_black_18dp.png b/res/drawable-xxhdpi/ic_expand_more_black_18dp.png
new file mode 100644
index 0000000..733c54c
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_expand_more_black_18dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_expand_more_black_24dp.png b/res/drawable-xxhdpi/ic_expand_more_black_24dp.png
new file mode 100644
index 0000000..aadd04a
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_expand_more_black_24dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_expand_more_grey600_18dp.png b/res/drawable-xxhdpi/ic_expand_more_grey600_18dp.png
new file mode 100644
index 0000000..0f0ddf7
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_expand_more_grey600_18dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_expand_more_grey600_24dp.png b/res/drawable-xxhdpi/ic_expand_more_grey600_24dp.png
new file mode 100644
index 0000000..921249f
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_expand_more_grey600_24dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_menu_expand_card_dark_normal.png b/res/drawable-xxhdpi/ic_menu_expand_card_dark_normal.png
index 784ab7f..bd48681 100644
--- a/res/drawable-xxhdpi/ic_menu_expand_card_dark_normal.png
+++ b/res/drawable-xxhdpi/ic_menu_expand_card_dark_normal.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_menu_expand_card_dark_pressed.png b/res/drawable-xxhdpi/ic_menu_expand_card_dark_pressed.png
index 7edf16f..c95eb4a 100644
--- a/res/drawable-xxhdpi/ic_menu_expand_card_dark_pressed.png
+++ b/res/drawable-xxhdpi/ic_menu_expand_card_dark_pressed.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_menu_overflow_card.png b/res/drawable-xxhdpi/ic_menu_overflow_card.png
new file mode 100644
index 0000000..0c951b9
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_menu_overflow_card.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_more_vert_black_18dp.png b/res/drawable-xxhdpi/ic_more_vert_black_18dp.png
new file mode 100644
index 0000000..050baec
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_more_vert_black_18dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_more_vert_black_24dp.png b/res/drawable-xxhdpi/ic_more_vert_black_24dp.png
new file mode 100644
index 0000000..d32453d
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_more_vert_black_24dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_more_vert_grey600_18dp.png b/res/drawable-xxhdpi/ic_more_vert_grey600_18dp.png
new file mode 100644
index 0000000..abd7493
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_more_vert_grey600_18dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_more_vert_grey600_24dp.png b/res/drawable-xxhdpi/ic_more_vert_grey600_24dp.png
new file mode 100644
index 0000000..44012b8
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_more_vert_grey600_24dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_chevron_right_grey600_24dp.png b/res/drawable-xxxhdpi/ic_chevron_right_grey600_24dp.png
new file mode 100644
index 0000000..a71c5b3
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_chevron_right_grey600_24dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_expand_less_black_24dp.png b/res/drawable-xxxhdpi/ic_expand_less_black_24dp.png
new file mode 100644
index 0000000..08ae545
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_expand_less_black_24dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_expand_less_grey600_24dp.png b/res/drawable-xxxhdpi/ic_expand_less_grey600_24dp.png
new file mode 100644
index 0000000..ed72b07
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_expand_less_grey600_24dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_expand_more_black_24dp.png b/res/drawable-xxxhdpi/ic_expand_more_black_24dp.png
new file mode 100644
index 0000000..228b2a9
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_expand_more_black_24dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_expand_more_grey600_24dp.png b/res/drawable-xxxhdpi/ic_expand_more_grey600_24dp.png
new file mode 100644
index 0000000..55f8396
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_expand_more_grey600_24dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_more_vert_black_24dp.png b/res/drawable-xxxhdpi/ic_more_vert_black_24dp.png
new file mode 100644
index 0000000..037b6f1
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_more_vert_black_24dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_more_vert_grey600_24dp.png b/res/drawable-xxxhdpi/ic_more_vert_grey600_24dp.png
new file mode 100644
index 0000000..0042578
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_more_vert_grey600_24dp.png
Binary files differ
diff --git a/res/drawable/activated_foreground_card.xml b/res/drawable/activated_foreground_card.xml
new file mode 100644
index 0000000..314f6bb
--- /dev/null
+++ b/res/drawable/activated_foreground_card.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@color/card_foreground_activated"/>
+ <corners android:radius="@dimen/card_background_default_radius"/>
+</shape>
diff --git a/res/drawable/activated_foreground_kitkat_card.xml b/res/drawable/activated_foreground_kitkat_card.xml
new file mode 100644
index 0000000..e83419d
--- /dev/null
+++ b/res/drawable/activated_foreground_kitkat_card.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@color/card_foreground_activated_kitkat"/>
+ <corners android:radius="@dimen/card_background_default_radius"/>
+</shape>
diff --git a/res/drawable/card_foreground_kitkat_selector.xml b/res/drawable/card_foreground_kitkat_selector.xml
index 8d79991..28b6259 100644
--- a/res/drawable/card_foreground_kitkat_selector.xml
+++ b/res/drawable/card_foreground_kitkat_selector.xml
@@ -21,7 +21,7 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:exitFadeDuration="@android:integer/config_mediumAnimTime">
- <item android:state_activated="true" android:drawable="@drawable/activated_background_kitkat_card"/>
+ <item android:state_activated="true" android:drawable="@drawable/activated_foreground_kitkat_card"/>
<item android:state_pressed="true" android:drawable="@drawable/pressed_background_kitkat_card"/>
<item android:drawable="@android:color/transparent"/>
-</selector> \ No newline at end of file
+</selector>
diff --git a/res/drawable/card_foreground_selector.xml b/res/drawable/card_foreground_selector.xml
index f8d73e0..958bac2 100644
--- a/res/drawable/card_foreground_selector.xml
+++ b/res/drawable/card_foreground_selector.xml
@@ -21,7 +21,7 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:exitFadeDuration="@android:integer/config_mediumAnimTime">
- <item android:state_activated="true" android:drawable="@drawable/activated_background_card"/>
+ <item android:state_activated="true" android:drawable="@drawable/activated_foreground_card"/>
<item android:state_pressed="true" android:drawable="@drawable/pressed_background_card"/>
<item android:drawable="@android:color/transparent"/>
-</selector> \ No newline at end of file
+</selector>
diff --git a/res/drawable/card_menu_button_expand_material.xml b/res/drawable/card_menu_button_expand_material.xml
new file mode 100644
index 0000000..a2cf1a5
--- /dev/null
+++ b/res/drawable/card_menu_button_expand_material.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:drawable="@drawable/ic_expand_more_black_24dp"
+ android:state_pressed="true"/>
+ <item android:drawable="@drawable/ic_expand_more_black_24dp"
+ android:state_focused="true"/>
+ <item android:drawable="@drawable/ic_expand_more_black_24dp"
+ android:state_selected="true"/>
+ <item android:drawable="@drawable/ic_expand_more_grey600_24dp"/>
+
+</selector> \ No newline at end of file
diff --git a/res/drawable/card_menu_button_expand_material_animator.xml b/res/drawable/card_menu_button_expand_material_animator.xml
new file mode 100644
index 0000000..fa923f4
--- /dev/null
+++ b/res/drawable/card_menu_button_expand_material_animator.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:drawable="@drawable/ic_expand_less_black_24dp"
+ android:state_pressed="true"/>
+ <item android:drawable="@drawable/ic_expand_less_black_24dp"
+ android:state_focused="true"/>
+ <item android:drawable="@drawable/ic_expand_less_black_24dp"
+ android:state_selected="true"/>
+ <item android:drawable="@drawable/ic_expand_more_grey600_24dp"/>
+
+</selector> \ No newline at end of file
diff --git a/res/drawable/card_menu_button_overflow_material.xml b/res/drawable/card_menu_button_overflow_material.xml
new file mode 100644
index 0000000..fa08832
--- /dev/null
+++ b/res/drawable/card_menu_button_overflow_material.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:drawable="@drawable/ic_more_vert_black_24dp"
+ android:state_pressed="true"/>
+ <item android:drawable="@drawable/ic_more_vert_black_24dp"
+ android:state_focused="true"/>
+ <item android:drawable="@drawable/ic_more_vert_black_24dp"
+ android:state_selected="true"/>
+ <item android:drawable="@drawable/ic_more_vert_grey600_24dp"/>
+
+</selector> \ No newline at end of file
diff --git a/res/drawable/card_menu_button_rounded_overflow_selector.xml b/res/drawable/card_menu_button_rounded_overflow_selector.xml
new file mode 100644
index 0000000..84917da
--- /dev/null
+++ b/res/drawable/card_menu_button_rounded_overflow_selector.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:drawable="@drawable/ic_more_vert_black_36dp"
+ android:state_pressed="true"/>
+ <item android:drawable="@drawable/ic_more_vert_black_36dp"
+ android:state_focused="true"/>
+ <item android:drawable="@drawable/ic_more_vert_black_36dp"
+ android:state_selected="true"/>
+ <item android:drawable="@drawable/ic_more_vert_grey600_36dp"/>
+
+</selector> \ No newline at end of file
diff --git a/res/drawable/native_card_selector.xml b/res/drawable/native_card_selector.xml
new file mode 100644
index 0000000..6f97f14
--- /dev/null
+++ b/res/drawable/native_card_selector.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:exitFadeDuration="@android:integer/config_mediumAnimTime">
+
+ <item android:state_activated="true" android:drawable="@color/card_activated"/>
+ <item android:state_pressed="true" android:drawable="@color/card_pressed"/>
+ <item android:drawable="@color/card_background"/>
+
+</selector> \ No newline at end of file
diff --git a/res/layout/base_header_layout.xml b/res/layout/base_header_layout.xml
index a031925..841d4fa 100644
--- a/res/layout/base_header_layout.xml
+++ b/res/layout/base_header_layout.xml
@@ -25,7 +25,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
- android:layout_alignParentStart="true"
+ android:layout_alignParentLeft="true"
style="@style/card.header_compound_view">
<!-- This is the Inner Content Header which you can populate runtime
@@ -42,7 +42,7 @@
android:id="@+id/card_header_button_frame"
style="@style/card.header_button_frame"
android:layout_alignParentTop="true"
- android:layout_alignParentEnd="true"
+ android:layout_alignParentRight="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
diff --git a/res/layout/base_list_expandable_children_layout.xml b/res/layout/base_list_expandable_children_layout.xml
new file mode 100644
index 0000000..708fa5d
--- /dev/null
+++ b/res/layout/base_list_expandable_children_layout.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="40dp"
+ android:clickable="true"
+ android:orientation="vertical"
+ android:paddingLeft="40dp"
+ tools:context=".MainActivity" >
+
+ <TextView
+ android:id="@+id/card_children_simple_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:drawablePadding="5dp"
+ android:gravity="center_vertical"
+ android:textSize="14sp"
+ android:textStyle="bold" >
+ </TextView>
+
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/base_section_layout.xml b/res/layout/base_section_layout.xml
new file mode 100644
index 0000000..46a5b34
--- /dev/null
+++ b/res/layout/base_section_layout.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ style="@style/card_section_container">
+
+
+ <TextView
+ android:id="@+id/card_section_simple_title"
+ style="@style/card_section_title"
+ />
+
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/base_withlist_empty.xml b/res/layout/base_withlist_empty.xml
new file mode 100644
index 0000000..cc6e4fc
--- /dev/null
+++ b/res/layout/base_withlist_empty.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ android:text="@string/card_empty_cardwithlist_text"
+ android:id="@+id/card_base_empty_cardwithlist_text"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/base_withlist_progress.xml b/res/layout/base_withlist_progress.xml
new file mode 100644
index 0000000..a258804
--- /dev/null
+++ b/res/layout/base_withlist_progress.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:gravity="center_horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <ProgressBar
+ style="?android:attr/progressBarStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical|center_horizontal"/>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical|center_horizontal"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:text="@string/card_progressbar_cardwithlist_text"
+ android:singleLine="true"
+ />
+
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/card_base_layout.xml b/res/layout/card_base_layout.xml
index 2a564b1..925caac 100644
--- a/res/layout/card_base_layout.xml
+++ b/res/layout/card_base_layout.xml
@@ -42,4 +42,4 @@
android:layout_height="wrap_content"/>
-</LinearLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/card_layout.xml b/res/layout/card_layout.xml
index 4ff042b..e0a128f 100644
--- a/res/layout/card_layout.xml
+++ b/res/layout/card_layout.xml
@@ -72,4 +72,4 @@
</FrameLayout>
-</LinearLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/card_overlay_layout.xml b/res/layout/card_overlay_layout.xml
index 00ea1d2..28d97a7 100644
--- a/res/layout/card_overlay_layout.xml
+++ b/res/layout/card_overlay_layout.xml
@@ -78,4 +78,4 @@
</FrameLayout>
-</LinearLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/card_thumbnail_layout.xml b/res/layout/card_thumbnail_layout.xml
index afc7bad..9c48a26 100644
--- a/res/layout/card_thumbnail_layout.xml
+++ b/res/layout/card_thumbnail_layout.xml
@@ -82,4 +82,4 @@
>
</FrameLayout>
-</LinearLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/card_thumbnail_overlay_layout.xml b/res/layout/card_thumbnail_overlay_layout.xml
index b0d6912..0567493 100644
--- a/res/layout/card_thumbnail_overlay_layout.xml
+++ b/res/layout/card_thumbnail_overlay_layout.xml
@@ -88,4 +88,4 @@
>
</FrameLayout>
-</LinearLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/inner_base_expand.xml b/res/layout/inner_base_expand.xml
index 1dfa2d2..219e2e6 100644
--- a/res/layout/inner_base_expand.xml
+++ b/res/layout/inner_base_expand.xml
@@ -30,4 +30,4 @@
android:id="@+id/card_expand_inner_simple_title"
style="@style/card.expand_simple_title"/>
-</LinearLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/inner_base_header.xml b/res/layout/inner_base_header.xml
index 4ae8b27..6d9d2f8 100644
--- a/res/layout/inner_base_header.xml
+++ b/res/layout/inner_base_header.xml
@@ -27,9 +27,11 @@
<!-- This is the base Inner View inside a CardHeader.
You can customize it with your layout xml file and your CardHeader.
- You can popolate your elements with CardHeader#setupInnerViewElements(android.view.ViewGroup, android.view.View) method -->
+ You can populate your elements with CardHeader#setupInnerViewElements(android.view.ViewGroup, android.view.View) method -->
<TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:id="@+id/card_header_inner_simple_title"
style="@style/card.header_simple_title"/>
-</LinearLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/inner_base_main.xml b/res/layout/inner_base_main.xml
index 90a0d57..d9cc34e 100644
--- a/res/layout/inner_base_main.xml
+++ b/res/layout/inner_base_main.xml
@@ -24,9 +24,9 @@
android:layout_height="wrap_content">
- <!-- This is the base Inner View inside a CardHeader.
- You can customize it with your layout xml file and your CardHeader.
- You can popolate your element with CardHeader#setupInnerViewElements() method -->
+ <!-- This is the base Inner View inside a Card.
+ You can customize it with your layout xml file and your Card.
+ You can populate your element with Card#setupInnerViewElements() method -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/res/layout/inner_base_main_cardwithlist.xml b/res/layout/inner_base_main_cardwithlist.xml
new file mode 100644
index 0000000..caa7235
--- /dev/null
+++ b/res/layout/inner_base_main_cardwithlist.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:card="http://schemas.android.com/apk/res-auto"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_marginLeft="@dimen/card_base_cardwithlist_layout_leftmargin"
+ android:layout_marginRight="@dimen/card_base_cardwithlist_layout_rightmargin"
+ android:layout_height="wrap_content">
+
+
+ <!-- This is the base Inner View inside a CardWithList.
+ You can customize it with your layout xml file using the CardWithList constructor.
+ If you change the id name, pay attention to update your getListViewId() method in your Card.
+ -->
+ <com.android.cards.prototypes.LinearListView
+ android:id="@+id/card_inner_base_main_cardwithlist"
+ style="@style/cardwithlist"
+ card:card_list_item_dividerHeight="@dimen/card_base_cardwithlist_dividerHeight"
+ />
+
+ <!-- This provide a default empty-view built-in feature.
+ You can customize this layout in manu ways. Check the doc-->
+ <ViewStub
+ android:id="@+id/card_inner_base_empty_cardwithlist"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ />
+
+ <ViewStub
+ android:id="@+id/card_inner_base_progressbar_cardwithlist"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:visibility="gone"
+ />
+
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/list_card_undo_material_message.xml b/res/layout/list_card_undo_material_message.xml
new file mode 100644
index 0000000..0f93e0c
--- /dev/null
+++ b/res/layout/list_card_undo_material_message.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ /*******************************************************************************
+ ~ Copyright (c) 2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ ******************************************************************************/
+ -->
+<!-- Use this layout for a default undo message -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/list_card_undobar"
+ style="@style/list_card_UndoBar_material"
+ android:orientation="horizontal">
+
+ <TextView
+ tools:text="Marked as read"
+ android:id="@+id/list_card_undobar_message"
+ android:fontFamily="@string/font_fontFamily_regular"
+ style="@style/list_card_UndoBarMessage_material"/>
+
+ <TextView
+ android:id="@+id/list_card_undobar_button"
+ android:fontFamily="@string/font_fontFamily_medium"
+ style="@style/list_card_UndoBarButton_material"/>
+
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/list_card_undo_materialmobile_message.xml b/res/layout/list_card_undo_materialmobile_message.xml
new file mode 100644
index 0000000..605f13d
--- /dev/null
+++ b/res/layout/list_card_undo_materialmobile_message.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ /*******************************************************************************
+ ~ Copyright (c) 2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ ******************************************************************************/
+ -->
+<!-- Use this layout for a default undo message -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/list_card_undobar"
+ style="@style/list_card_UndoBar_materialmobile"
+ android:orientation="horizontal">
+
+ <TextView
+ tools:text="Marked as read"
+ android:id="@+id/list_card_undobar_message"
+ android:fontFamily="@string/font_fontFamily_regular"
+ style="@style/list_card_UndoBarMessage_materialmobile"/>
+
+ <TextView
+ android:id="@+id/list_card_undobar_button"
+ android:fontFamily="@string/font_fontFamily_medium"
+ style="@style/list_card_UndoBarButton_materialmobile"/>
+
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/native_base_header_layout.xml b/res/layout/native_base_header_layout.xml
new file mode 100644
index 0000000..aec3528
--- /dev/null
+++ b/res/layout/native_base_header_layout.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<!-- This is the Header Layout
+ If you customize your header layout, if you want to preserve built-in feature use same IDs.
+ -->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentLeft="true"
+ style="@style/card.native.header_compound_view">
+
+ <!-- This is the Inner Content Header which you can populate runtime
+ with setupInnerViewElements(android.view.ViewGroup, android.view.View) method in CardHeader class.-->
+ <FrameLayout
+ android:id="@+id/card_header_inner_frame"
+ style="@style/card.native.header_inner_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+
+
+ <!-- This is the Button Frame.
+ You can custom its behaviour with some methods in CardHeader class -->
+ <FrameLayout
+ android:id="@+id/card_header_button_frame"
+ style="@style/card.native.header_button_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <!-- overflow button. It has a Popup Menu -->
+ <ImageButton
+ android:id="@+id/card_header_button_overflow"
+ style="@style/card.native.header_button_base.overflow"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+
+ <!-- Expand/Collapse button. It shows/hides a Hidden Frame-->
+ <ImageButton
+ android:id="@+id/card_header_button_expand"
+ style="@style/card.native.header_button_base.expand"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+
+ <!-- Other button. You can customize it with your style file -->
+ <ImageButton
+ android:id="@+id/card_header_button_other"
+ style="@style/card.native.header_button_base.other"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+ </FrameLayout>
+
+</RelativeLayout>
+
diff --git a/res/layout/native_base_thumbnail_layout.xml b/res/layout/native_base_thumbnail_layout.xml
new file mode 100644
index 0000000..553cfdd
--- /dev/null
+++ b/res/layout/native_base_thumbnail_layout.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<ImageView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/card_thumbnail_image"
+ style="@style/card.native.card_thumbnail_image"/>
+
+
diff --git a/res/layout/native_card_layout.xml b/res/layout/native_card_layout.xml
new file mode 100644
index 0000000..6dee707
--- /dev/null
+++ b/res/layout/native_card_layout.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:card="http://schemas.android.com/apk/res-auto"
+ android:orientation="vertical"
+ style="@style/card.native"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <!-- Card visible layout -->
+ <com.android.cards.view.ForegroundLinearLayout
+ android:id="@+id/card_main_layout"
+ style="@style/card.native.main_layout_foreground"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ >
+
+ <!-- Compound view for Header Card
+ If you want to customize this element use attr card:card_header_layout_resourceID
+ You can also use your CardHeader subclass-->
+ <com.android.cards.view.component.CardHeaderView
+ style="@style/card.native.header_outer_layout"
+ android:id="@+id/card_header_layout"
+ android:layout_width="match_parent"
+ card:card_header_layout_resourceID="@layout/native_base_header_layout"
+ android:layout_height="wrap_content"/>
+
+ <!-- Main Content View -->
+ <FrameLayout
+ android:id="@+id/card_main_content_layout"
+ style="@style/card.native.content_outer_layout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+
+ </com.android.cards.view.ForegroundLinearLayout>
+
+ <!-- Expand layout. You can customize this element with your CardExpand class -->
+ <FrameLayout
+ android:id="@+id/card_content_expand_layout"
+ style="@style/card.native.main_contentExpand"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ >
+
+ </FrameLayout>
+
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/native_card_thumbnail_layout.xml b/res/layout/native_card_thumbnail_layout.xml
new file mode 100644
index 0000000..2a36b6b
--- /dev/null
+++ b/res/layout/native_card_thumbnail_layout.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:card="http://schemas.android.com/apk/res-auto"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <!-- Card visible layout -->
+ <com.android.cards.view.ForegroundLinearLayout
+ android:id="@+id/card_main_layout"
+ style="@style/card.native.main_layout_foreground"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ >
+
+ <!-- Compound view for Header Card
+ If you want to customize this element use attr card:card_header_layout_resourceID
+ You can also use your CardHeader subclass-->
+ <com.android.cards.view.component.CardHeaderView
+ style="@style/card.native.header_outer_layout"
+ android:id="@+id/card_header_layout"
+ android:layout_width="match_parent"
+ card:card_header_layout_resourceID="@layout/native_base_header_layout"
+ android:layout_height="wrap_content"/>
+
+ <LinearLayout
+ android:id="@+id/card_thumb_and_content_layout"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <com.android.cards.view.component.CardThumbnailView
+ style="@style/card.native.card_thumbnail_outer_layout"
+ android:id="@+id/card_thumbnail_layout"
+ android:layout_width="wrap_content"
+ card:card_thumbnail_layout_resourceID="@layout/native_base_thumbnail_layout"
+ android:layout_height="match_parent"/>
+
+ <!-- Main Content View -->
+ <FrameLayout
+ android:id="@+id/card_main_content_layout"
+ style="@style/card.native.content_outer_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+
+ </LinearLayout>
+
+ </com.android.cards.view.ForegroundLinearLayout>
+
+ <!-- Expand layout. You can customize this element with your CardExpand class -->
+ <FrameLayout
+ android:id="@+id/card_content_expand_layout"
+ style="@style/card.native.main_contentExpand"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ >
+ </FrameLayout>
+
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/native_cardwithlist_layout.xml b/res/layout/native_cardwithlist_layout.xml
new file mode 100644
index 0000000..611b8b7
--- /dev/null
+++ b/res/layout/native_cardwithlist_layout.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:card="http://schemas.android.com/apk/res-auto"
+ android:orientation="vertical"
+ style="@style/card.native"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <!-- Card visible layout -->
+ <com.android.cards.view.ForegroundLinearLayout
+ android:id="@+id/card_main_layout"
+ style="@style/card.native.main_layout_foreground"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ >
+
+ <!-- Compound view for Header Card
+ If you want to customize this element use attr card:card_header_layout_resourceID
+ You can also use your CardHeader subclass-->
+ <com.android.cards.view.component.CardHeaderView
+ style="@style/card.native.header_outer_layout"
+ android:id="@+id/card_header_layout"
+ android:layout_width="match_parent"
+ card:card_header_layout_resourceID="@layout/native_base_header_layout"
+ android:layout_height="wrap_content"/>
+
+ <!-- Main Content View -->
+ <FrameLayout
+ android:id="@+id/card_main_content_layout"
+ style="@style/card.native.content_outer_layout.cardwithlist"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+
+ </com.android.cards.view.ForegroundLinearLayout>
+
+ <!-- Expand layout. You can customize this element with your CardExpand class -->
+ <FrameLayout
+ android:id="@+id/card_content_expand_layout"
+ style="@style/card.native.main_contentExpand"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ >
+ </FrameLayout>
+
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/native_inner_base_expand.xml b/res/layout/native_inner_base_expand.xml
new file mode 100644
index 0000000..6fa78d1
--- /dev/null
+++ b/res/layout/native_inner_base_expand.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<!-- This is the InnerContent of Expand/Collapse Area -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/card_expand_inner_simple_title"
+ style="@style/card.native.expand_simple_title"/>
+
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/native_inner_base_header.xml b/res/layout/native_inner_base_header.xml
new file mode 100644
index 0000000..87fdb64
--- /dev/null
+++ b/res/layout/native_inner_base_header.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<!-- This is the InnerContent of Header -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+
+ <!-- This is the base Inner View inside a CardHeader.
+ You can customize it with your layout xml file and your CardHeader.
+ You can populate your elements with CardHeader#setupInnerViewElements(android.view.ViewGroup, android.view.View) method -->
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/card_header_inner_simple_title"
+ style="@style/card.native.header_simple_title"/>
+
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/native_inner_base_main.xml b/res/layout/native_inner_base_main.xml
new file mode 100644
index 0000000..43c74b2
--- /dev/null
+++ b/res/layout/native_inner_base_main.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+
+ <!-- This is the base Inner View inside a Card.
+ You can customize it with your layout xml file and your Card.
+ You can populate your element with Card#setupInnerViewElements() method -->
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/card_main_inner_simple_title"
+ style="@style/card.native.base_simple_title"/>
+
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/native_inner_base_main_cardwithlist.xml b/res/layout/native_inner_base_main_cardwithlist.xml
new file mode 100644
index 0000000..77bbbbd
--- /dev/null
+++ b/res/layout/native_inner_base_main_cardwithlist.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:card="http://schemas.android.com/apk/res-auto"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_marginLeft="@dimen/card_base_cardwithlist_layout_leftmargin"
+ android:layout_marginRight="@dimen/card_base_cardwithlist_layout_rightmargin"
+ android:layout_height="wrap_content">
+
+
+ <!-- This is the base Inner View inside a CardWithList.
+ You can customize it with your layout xml file using the CardWithList constructor.
+ If you change the id name, pay attention to update your getListViewId() method in your Card.
+ -->
+ <com.android.cards.prototypes.LinearListView
+ android:id="@+id/card_inner_base_main_cardwithlist"
+ style="@style/native_cardwithlist"
+ card:card_list_item_dividerHeight="@dimen/card_base_cardwithlist_dividerHeight"
+ />
+
+ <!-- This provide a default empty-view built-in feature.
+ You can customize this layout in manu ways. Check the doc-->
+ <ViewStub
+ android:id="@+id/card_inner_base_empty_cardwithlist"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ />
+
+ <ViewStub
+ android:id="@+id/card_inner_base_progressbar_cardwithlist"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:visibility="gone"
+ />
+
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/native_list_card_layout.xml b/res/layout/native_list_card_layout.xml
new file mode 100644
index 0000000..ecef674
--- /dev/null
+++ b/res/layout/native_list_card_layout.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<!-- You can customize this layout.
+ You need to have in your layout a `CardView` with the ID `list_cardId` -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent">
+
+ <com.android.cards.view.CardViewNative
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:card="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/list_cardId"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@style/native_list_card.base"
+ card:card_layout_resourceID="@layout/native_card_layout"/>
+
+</LinearLayout>
diff --git a/res/layout/native_list_card_thumbnail_layout.xml b/res/layout/native_list_card_thumbnail_layout.xml
new file mode 100644
index 0000000..a9b6bdc
--- /dev/null
+++ b/res/layout/native_list_card_thumbnail_layout.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<!-- You can customize this layout.
+ You need to have in your layout a `CardView` with the ID `list_cardId` -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent">
+
+<com.android.cards.view.CardViewNative
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:card="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/list_cardId"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@style/native_list_card.thumbnail"
+ card:card_layout_resourceID="@layout/native_card_thumbnail_layout"
+ />
+
+
+</LinearLayout> \ No newline at end of file
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
new file mode 100644
index 0000000..1281dd4
--- /dev/null
+++ b/res/values-de/strings.xml
@@ -0,0 +1,41 @@
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<resources>
+
+
+ <!-- Undo Controller-->
+
+ <string name="list_card_undo_title">Rückgängig</string>
+ <!--<string name="undo_card">Karte entfernt</string>-->
+
+ <plurals name="list_card_undo_items">
+ <item quantity="one">1 Karte entfernt</item>
+ <item quantity="other">%d Karten entfernt</item>
+ </plurals>
+
+ <!-- Card selected item with CAB -->
+ <plurals name="card_selected_items">
+ <item quantity="one">1 Element gewählt</item>
+ <item quantity="other">%d Elemente gewählt</item>
+ </plurals>
+
+
+
+
+</resources>
diff --git a/res/values-v16/fonts.xml b/res/values-v16/fonts.xml
new file mode 100644
index 0000000..98bd445
--- /dev/null
+++ b/res/values-v16/fonts.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<resources>
+ <string name="card_font_fontFamily_header">sans-serif-condensed</string>
+ <string name="card_native_font_fontFamily_header">sans-serif-medium</string>
+
+ <string name="card_font_fontFamily_main_content">sans-serif</string>
+ <string name="card_native_font_fontFamily_main_content">sans-serif</string>
+
+ <string name="card_font_fontFamily_expand">sans-serif-condensed</string>
+ <string name="card_native_font_fontFamily_expand">sans-serif</string>
+</resources> \ No newline at end of file
diff --git a/res/values-v16/styles.xml b/res/values-v16/styles.xml
new file mode 100644
index 0000000..66eadac
--- /dev/null
+++ b/res/values-v16/styles.xml
@@ -0,0 +1,99 @@
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<resources>
+
+ <style name="card"></style>
+
+
+ <!-- Style for Header ******************************************************-->
+
+ <!--Style for simple title header inner view-->
+ <style name="card.header_simple_title">
+ <item name="android:layout_gravity">left|center_vertical</item>
+ <item name="android:fontFamily">@string/card_font_fontFamily_header</item>
+ <item name="android:textColor">@color/card_text_color_header</item>
+ <item name="android:textSize">@dimen/card_header_simple_title_text_size</item>
+ <item name="android:layout_marginLeft">@dimen/card_header_simple_title_margin_left</item>
+ <item name="android:layout_marginTop">@dimen/card_header_simple_title_margin_top</item>
+ <item name="android:layout_marginRight">@dimen/card_header_simple_title_margin_right</item>
+ <item name="android:layout_marginBottom">@dimen/card_header_simple_title_margin_bottom</item>
+ </style>
+
+ <style name="card.native.header_simple_title" >
+ <item name="android:layout_gravity">left|center_vertical</item>
+ <item name="android:textSize">@dimen/card_header_native_simple_title_text_size</item>
+ <item name="android:textColor">@color/card_text_color_header</item>
+ <item name="android:fontFamily">@string/card_native_font_fontFamily_header</item>
+ <item name="android:layout_marginLeft">@dimen/card_header_native_simple_title_margin_left</item>
+ <item name="android:layout_marginTop">@dimen/card_header_native_simple_title_margin_top</item>
+ <item name="android:layout_marginRight">@dimen/card_header_native_simple_title_margin_right</item>
+ <item name="android:layout_marginBottom">@dimen/card_header_native_simple_title_margin_bottom</item>
+ </style>
+
+
+ <!-- Style for Content ******************************************************-->
+
+ <!--Style for simple title inner main view-->
+ <style name="card.base_simple_title">
+ <item name="android:textStyle">bold</item>
+ <item name="android:fontFamily">@string/card_font_fontFamily_main_content</item>
+ <item name="android:layout_gravity">left|center_vertical</item>
+ <item name="android:layout_marginLeft">@dimen/card_main_simple_title_margin_left</item>
+ <item name="android:layout_marginTop">@dimen/card_main_simple_title_margin_top</item>
+ <item name="android:layout_marginRight">@dimen/card_main_simple_title_margin_right</item>
+ <item name="android:layout_marginBottom">@dimen/card_main_simple_title_margin_bottom</item>
+ </style>
+
+ <!--Style for simple title inner main view-->
+ <style name="card.native.base_simple_title">
+ <item name="android:textStyle">bold</item>
+ <item name="android:fontFamily">@string/card_native_font_fontFamily_main_content</item>
+ <item name="android:textSize">@dimen/card_main_content_native_simple_title_text_size</item>
+ <item name="android:layout_gravity">left|center_vertical</item>
+ <item name="android:layout_marginLeft">@dimen/card_main_native_simple_title_margin_left</item>
+ <item name="android:layout_marginTop">@dimen/card_main_native_simple_title_margin_top</item>
+ <item name="android:layout_marginRight">@dimen/card_header_native_simple_title_margin_right</item>
+ <item name="android:layout_marginBottom">@dimen/card_header_native_simple_title_margin_bottom</item>
+ </style>
+
+ <!-- Style for Expand/Collapse *************************************************-->
+
+ <!--Style for simple title expand/collapse inner view-->
+ <style name="card.expand_simple_title">
+ <item name="android:layout_gravity">left|center_vertical</item>
+ <item name="android:gravity">center_vertical</item>
+ <item name="android:fontFamily">@string/card_font_fontFamily_expand</item>
+ <item name="android:textSize">@dimen/card_expand_simple_title_text_size</item>
+ <item name="android:paddingLeft">@dimen/card_expand_simple_title_paddingLeft</item>
+ <item name="android:paddingRight">@dimen/card_expand_simple_title_paddingRight</item>
+ <item name="android:textColor">@color/card_expand_title_color</item>
+ </style>
+
+ <!--Style for simple title expand/collapse inner view-->
+ <style name="card.native.expand_simple_title">
+ <item name="android:layout_gravity">left|center_vertical</item>
+ <item name="android:gravity">center_vertical</item>
+ <item name="android:textSize">@dimen/card_expand_native_simple_title_text_size</item>
+ <item name="android:paddingLeft">@dimen/card_expand_native_simple_title_padding_left</item>
+ <item name="android:paddingRight">@dimen/card_expand_native_simple_title_padding_right</item>
+ <item name="android:textColor">@color/card_expand_title_color</item>
+ <item name="android:fontFamily">@string/card_native_font_fontFamily_expand</item>
+ </style>
+
+</resources>
diff --git a/res/values-v21/fonts.xml b/res/values-v21/fonts.xml
new file mode 100644
index 0000000..226c74b
--- /dev/null
+++ b/res/values-v21/fonts.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<resources>
+ <string name="card_font_fontFamily_header">sans-serif-condensed</string>
+ <string name="card_native_font_fontFamily_header">sans-serif-medium</string>
+
+ <string name="card_font_fontFamily_main_content">sans-serif</string>
+ <string name="card_native_font_fontFamily_main_content">sans-serif</string>
+</resources> \ No newline at end of file
diff --git a/res/values-v21/styles.xml b/res/values-v21/styles.xml
new file mode 100644
index 0000000..51fa5e0
--- /dev/null
+++ b/res/values-v21/styles.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<resources>
+
+ <!-- Button Base in Header-->
+ <style name="card.header_button_base">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_alignParentRight">true</item>
+ <item name="android:paddingLeft">@dimen/card_header_button_padding_left</item>
+ <item name="android:focusable">false</item>
+ <item name="android:focusableInTouchMode">false</item>
+ <item name="android:clickable">true</item>
+ <item name="android:layout_centerVertical">true</item>
+ <item name="android:layout_gravity">center_vertical</item>
+ <item name="android:layout_marginRight">@dimen/card_header_button_margin_right</item>
+ <item name="android:background">?android:attr/selectableItemBackgroundBorderless</item>
+ </style>
+
+ <style name="card.native.header_button_base">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_alignParentRight">true</item>
+ <item name="android:focusable">false</item>
+ <item name="android:focusableInTouchMode">false</item>
+ <item name="android:clickable">true</item>
+ <item name="android:layout_centerVertical">true</item>
+ <item name="android:layout_gravity">center_vertical</item>
+ <item name="android:background">?android:attr/selectableItemBackgroundBorderless</item>
+ <item name="android:layout_marginLeft">@dimen/card_header_native_button_margin_left</item>
+ <item name="android:layout_marginRight">@dimen/card_header_native_button_margin_right</item>
+ <item name="android:paddingLeft">0dp</item>
+ </style>
+
+ <!-- Button Overflow in Header -->
+ <style name="card.header_button_base.overflow" >
+ <item name="android:src">@drawable/ic_menu_overflow_card_rounded_dark_normal</item>
+ </style>
+
+ <style name="card.native.header_button_base.overflow" >
+ <item name="android:src">@drawable/card_menu_button_overflow_material</item>
+ </style>
+
+ <!-- Button to Expand/Collapse in Header -->
+ <style name="card.header_button_base.expand">
+ <item name="android:src">@drawable/ic_menu_expand_card_dark_normal</item>
+ </style>
+
+ <style name="card.native.header_button_base.expand">
+ <item name="android:src">@drawable/card_menu_button_expand_material_animator</item>
+ </style>
+
+
+ <!-- Style for Main Layout ****************************************-->
+
+</resources> \ No newline at end of file
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 0ab9e6a..b33ea39 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -34,6 +34,9 @@
<!-- Layout used by card in a ListView. Default value is @layout/list_card_layout -->
<attr name="list_card_layout_resourceID" format="reference"/>
+ <!-- Layout used by card in a ListView. Default value is @layout/list_card_layout -->
+ <attr name="list_card_layout_resourceIDs" format="reference"/>
+
</declare-styleable>
<!-- Used for ForegroundLinearLayout -->
@@ -44,5 +47,10 @@
<attr name="android:foregroundGravity" />
</declare-styleable>
+ <!-- Used in card with list-->
+ <declare-styleable name="card_listItem">
+ <!-- Height of divider used in the list -->
+ <attr name="card_list_item_dividerHeight" format="dimension" />
+ </declare-styleable>
</resources> \ No newline at end of file
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 4937c53..3cd6bab 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -21,6 +21,7 @@
<color name="card_background">#FFF</color>
<color name="card_background_header">#FFF</color>
<color name="card_backgroundExpand">#515254</color>
+ <color name="card_native_background">@android:color/transparent</color>
<color name="card_text_color_header">#000</color>
<color name="card_expand_title_color">#B3B2B2</color>
@@ -28,8 +29,23 @@
<!-- Used by selector -->
<color name="card_pressed">#7E0099CC</color>
<color name="card_activated">#CFE9F3</color>
+ <color name="card_foreground_activated">#99CFE9F3</color>
<color name="card_pressed_kitkat">#10000000</color>
<color name="card_activated_kitkat">#ADE1F4</color>
+ <color name="card_foreground_activated_kitkat">#99ADE1F4</color>
-</resources> \ No newline at end of file
+ <!-- Used by card with list -->
+ <color name="card_base_cardwithlist_divider_color">#E5E5E5</color>
+ <color name="card_base_cardwithlist_background_list_color">#10000000</color>
+
+ <color name="card_native_base_cardwithlist_divider_color">#E5E5E5</color>
+ <color name="card_native_base_cardwithlist_background_list_color">#10000000</color>
+
+ <!-- Used by sectioned list -->
+ <color name="card_section_container_color">#10000000</color>
+ <color name="card_section_title_color">@android:color/black</color>
+
+
+
+</resources>
diff --git a/res/values/colors_undo.xml b/res/values/colors_undo.xml
new file mode 100644
index 0000000..3af0abc
--- /dev/null
+++ b/res/values/colors_undo.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ /*******************************************************************************
+ ~ Copyright (c) 2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ ******************************************************************************/
+ -->
+
+<resources>
+ <color name="card_undobar_material_text_color">#4CAF50</color>
+ <color name="card_undobar_material_background_color">#323232</color>
+</resources> \ No newline at end of file
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 74bd074..b05ddf1 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -21,50 +21,95 @@
<!-- Card -->
<dimen name="card_base_empty_height">96dp</dimen>
- <dimen name="card_background_default_radius">2dip</dimen>
+ <dimen name="card_background_default_radius">2dp</dimen>
+
+ <!-- Native card margin -->
+ <dimen name="card_default_native_margin_top">12dp</dimen>
+ <dimen name="card_default_native_margin_bottom">12dp</dimen>
+ <dimen name="card_default_native_margin_left">8dp</dimen>
+ <dimen name="card_default_native_margin_right">8dp</dimen>
<!-- Main -->
<dimen name="card_main_layout_view_margin_top">0dp</dimen>
- <dimen name="card_main_layout_view_margin_start">0dp</dimen>
+ <dimen name="card_main_layout_view_margin_left">0dp</dimen>
<dimen name="card_main_layout_view_margin_bottom">0dp</dimen>
- <dimen name="card_main_layout_view_margin_end">0dp</dimen>
+ <dimen name="card_main_layout_view_margin_right">0dp</dimen>
+
+ <dimen name="card_main_layout_native_view_margin_top">0dp</dimen>
+ <dimen name="card_main_layout_native_view_margin_left">0dp</dimen>
+ <dimen name="card_main_layout_native_view_margin_bottom">0dp</dimen>
+ <dimen name="card_main_layout_native_view_margin_right">0dp</dimen>
<!-- Header -->
+ <dimen name="card_header_default_padding">12dp</dimen>
+ <dimen name="card_header_native_default_paddingLeft">12dp</dimen>
+ <dimen name="card_header_native_default_paddingRight">12dp</dimen>
+ <dimen name="card_header_native_default_paddingTop">12dp</dimen>
+ <dimen name="card_header_native_default_paddingBottom">0dp</dimen>
+
<dimen name="card_header_outer_view_margin_top">0dp</dimen>
- <dimen name="card_header_outer_view_margin_start">0dp</dimen>
+ <dimen name="card_header_outer_view_margin_left">0dp</dimen>
<dimen name="card_header_outer_view_margin_bottom">0dp</dimen>
- <dimen name="card_header_outer_view_margin_end">0dp</dimen>
+ <dimen name="card_header_outer_view_margin_right">0dp</dimen>
<!--Button Header -->
- <dimen name="card_header_button_padding_start">10dp</dimen>
- <dimen name="card_header_button_padding_end">0dp</dimen>
+ <dimen name="card_header_button_padding_left">10dp</dimen>
+ <dimen name="card_header_button_padding_right">0dp</dimen>
<dimen name="card_header_button_padding_bottom">0dp</dimen>
<dimen name="card_header_button_padding_top">0dp</dimen>
- <dimen name="card_header_button_margin_end">2dp</dimen>
- <dimen name="card_header_button_overflow_margin_end">3dp</dimen>
+ <dimen name="card_header_button_margin_right">2dp</dimen>
+ <dimen name="card_header_button_overflow_margin_right">3dp</dimen>
+
+ <dimen name="card_header_native_button_margin_right">0dp</dimen>
+ <dimen name="card_header_native_button_margin_left">0dp</dimen>
<!-- Title Header -->
- <dimen name="card_header_simple_title_margin_start">10dp</dimen>
+ <dimen name="card_header_simple_title_margin_left">10dp</dimen>
<dimen name="card_header_simple_title_margin_top">5dp</dimen>
- <dimen name="card_header_simple_title_text_size">20sp</dimen>
- <dimen name="card_header_simple_title_margin_end">20dp</dimen>
+ <dimen name="card_header_simple_title_margin_right">20dp</dimen>
<dimen name="card_header_simple_title_margin_bottom">0dp</dimen>
+ <dimen name="card_header_simple_title_text_size">20sp</dimen>
+
+ <dimen name="card_header_native_simple_title_margin_left">0dp</dimen>
+ <dimen name="card_header_native_simple_title_margin_top">0dp</dimen>
+ <dimen name="card_header_native_simple_title_margin_right">0dp</dimen>
+ <dimen name="card_header_native_simple_title_margin_bottom">0dp</dimen>
+ <dimen name="card_header_native_simple_title_margin">0dp</dimen>
+ <dimen name="card_header_native_simple_title_text_size">18sp</dimen>
<!-- Content -->
<dimen name="card_content_outer_view_margin_top">0dp</dimen>
- <dimen name="card_content_outer_view_margin_start">0dp</dimen>
+ <dimen name="card_content_outer_view_margin_left">0dp</dimen>
<dimen name="card_content_outer_view_margin_bottom">0dp</dimen>
- <dimen name="card_content_outer_view_margin_end">0dp</dimen>
+ <dimen name="card_content_outer_view_margin_right">0dp</dimen>
+
+ <dimen name="card_main_content_native_default_paddingLeft">12dp</dimen>
+ <dimen name="card_main_content_native_default_paddingRight">12dp</dimen>
+ <dimen name="card_main_content_native_default_paddingTop">12dp</dimen>
+ <dimen name="card_main_content_native_default_paddingBottom">12dp</dimen>
+
+ <dimen name="card_main_content_native_cardwithlist_paddingLeft">0dp</dimen>
+ <dimen name="card_main_content_native_cardwithlist_paddingRight">0dp</dimen>
+ <dimen name="card_main_content_native_cardwithlist_paddingTop">12dp</dimen>
+ <dimen name="card_main_content_native_cardwithlist_paddingBottom">12dp</dimen>
+
- <dimen name="card_main_simple_title_margin_start">5dp</dimen>
+ <dimen name="card_main_simple_title_margin_left">5dp</dimen>
<dimen name="card_main_simple_title_margin_top">0dp</dimen>
+ <dimen name="card_main_simple_title_margin_right">0dp</dimen>
+ <dimen name="card_main_simple_title_margin_bottom">0dp</dimen>
+
+ <dimen name="card_main_native_simple_title_margin_left">0dp</dimen>
+ <dimen name="card_main_native_simple_title_margin_top">0dp</dimen>
+
+ <dimen name="card_main_content_native_simple_title_text_size">16sp</dimen>
<!-- Shadow -->
<dimen name="card_shadow_height">3dp</dimen>
<dimen name="card_shadow_view_margin_top">0dp</dimen>
- <dimen name="card_shadow_view_margin_start">@dimen/card_background_default_radius</dimen>
+ <dimen name="card_shadow_view_margin_left">@dimen/card_background_default_radius</dimen>
<dimen name="card_shadow_view_margin_bottom">0dp</dimen>
- <dimen name="card_shadow_view_margin_end">@dimen/card_background_default_radius</dimen>
+ <dimen name="card_shadow_view_margin_right">@dimen/card_background_default_radius</dimen>
<!-- Thumbnail -->
<dimen name="card_thumbnail_width">72dp</dimen>
@@ -72,23 +117,60 @@
<!-- Expand -->
<dimen name="card_expand_layout_padding">2dp</dimen>
- <dimen name="card_expand_simple_title_paddingStart">10dp</dimen>
- <dimen name="card_expand_simple_title_paddingEnd">10dp</dimen>
+ <dimen name="card_expand_simple_title_paddingLeft">10dp</dimen>
+ <dimen name="card_expand_simple_title_paddingRight">10dp</dimen>
<dimen name="card_expand_simple_title_text_size">14sp</dimen>
+ <dimen name="card_expand_native_layout_padding_left">12dp</dimen>
+ <dimen name="card_expand_native_layout_padding_right">12dp</dimen>
+ <dimen name="card_expand_native_layout_padding_top">12dp</dimen>
+ <dimen name="card_expand_native_layout_padding_bottom">12dp</dimen>
+
+ <dimen name="card_expand_native_margin_right">0dp</dimen>
+ <dimen name="card_expand_native_margin_left">0dp</dimen>
+ <dimen name="card_expand_native_simple_title_text_size">14sp</dimen>
+ <dimen name="card_expand_native_simple_title_padding_left">0dp</dimen>
+ <dimen name="card_expand_native_simple_title_padding_right">0dp</dimen>
<!-- List -->
- <dimen name="list_card_padding_start">8dp</dimen>
- <dimen name="list_card_padding_end">8dp</dimen>
+ <dimen name="list_card_padding_left">8dp</dimen>
+ <dimen name="list_card_padding_right">8dp</dimen>
<dimen name="list_card_padding_bottom">6dp</dimen>
<dimen name="list_card_padding_top">2dp</dimen>
+ <!-- List -->
+ <dimen name="native_list_card_margin_left">0dp</dimen>
+ <dimen name="native_list_card_margin_right">0dp</dimen>
+ <dimen name="native_list_card_margin_bottom">6dp</dimen>
+ <dimen name="native_list_card_margin_top">6dp</dimen>
+
+ <!-- RecyclerView -->
+ <dimen name="native_recyclerview_card_margin_left">0dp</dimen>
+ <dimen name="native_recyclerview_card_margin_right">0dp</dimen>
+ <dimen name="native_recyclerview_card_margin_bottom">6dp</dimen>
+ <dimen name="native_recyclerview_card_margin_top">6dp</dimen>
+
<!-- Grid -->
- <dimen name="grid_card_padding_start">2dp</dimen>
- <dimen name="grid_card_padding_end">2dp</dimen>
+ <dimen name="grid_card_padding_left">2dp</dimen>
+ <dimen name="grid_card_padding_right">2dp</dimen>
<dimen name="grid_card_padding_bottom">2dp</dimen>
<dimen name="grid_card_padding_top">2dp</dimen>
+ <!-- Card with list -->
+ <dimen name="card_base_cardwithlist_layout_leftmargin">0dp</dimen>
+ <dimen name="card_base_cardwithlist_layout_rightmargin">0dp</dimen>
+ <dimen name="card_base_cardwithlist_list_margin_top">10dp</dimen>
+ <dimen name="card_base_cardwithlist_list_margin_left">0dp</dimen>
+
+ <dimen name="card_base_cardwithlist_dividerHeight">1dp</dimen>
+
+
+ <!--Section -->
+ <dimen name="card_section_title">18sp</dimen>
+ <dimen name="card_section_container_padding_left">15dp</dimen>
+ <dimen name="card_section_container_padding_right">15dp</dimen>
+ <dimen name="card_section_title_margin_top">10dp</dimen>
+
-</resources>
+</resources> \ No newline at end of file
diff --git a/res/values/fonts.xml b/res/values/fonts.xml
new file mode 100644
index 0000000..3d5bf60
--- /dev/null
+++ b/res/values/fonts.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ /*******************************************************************************
+ ~ Copyright (c) 2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ ******************************************************************************/
+ -->
+
+<resources>
+ <string name="font_fontFamily_regular">sans-serif</string>
+ <string name="font_fontFamily_medium">sans-serif</string>
+</resources> \ No newline at end of file
diff --git a/res/values/integers.xml b/res/values/integers.xml
new file mode 100644
index 0000000..32779ba
--- /dev/null
+++ b/res/values/integers.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<resources>
+ <integer name="list_card_swipe_distance_divisor">2</integer>
+</resources> \ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 0ac9f34..8a7847d 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -17,8 +17,6 @@
-->
<resources>
-
- <string name="app_name">CardsLib</string>
<!-- Undo Controller-->
@@ -37,7 +35,9 @@
<item quantity="other">%d items selected</item>
</plurals>
-
+ <!-- Card with List -->
+ <string name="card_empty_cardwithlist_text">No data....</string>
+ <string name="card_progressbar_cardwithlist_text">Loading data...</string>
</resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 9c04d11..5fe4d68 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -19,7 +19,18 @@
<resources>
<style name="card">
+ <!-- this style should be empty -->
+ </style>
+
+ <style name="card.native">
+ <!-- this style should be empty -->
+ </style>
+ <style name="card_external">
+ <item name="android:layout_marginTop">@dimen/card_default_native_margin_top</item>
+ <item name="android:layout_marginBottom">@dimen/card_default_native_margin_bottom</item>
+ <item name="android:layout_marginLeft">@dimen/card_default_native_margin_left</item>
+ <item name="android:layout_marginRight">@dimen/card_default_native_margin_right</item>
</style>
<!-- Style for Shadow ******************************************************-->
@@ -28,8 +39,8 @@
<style name="card.shadow_outer_layout">
<item name="android:layout_marginTop">@dimen/card_shadow_view_margin_top</item>
<item name="android:layout_marginBottom">@dimen/card_shadow_view_margin_bottom</item>
- <item name="android:layout_marginStart">@dimen/card_shadow_view_margin_start</item>
- <item name="android:layout_marginEnd">@dimen/card_shadow_view_margin_end</item>
+ <item name="android:layout_marginLeft">@dimen/card_shadow_view_margin_left</item>
+ <item name="android:layout_marginRight">@dimen/card_shadow_view_margin_right</item>
</style>
<!--Style for shadow image-->
@@ -42,11 +53,26 @@
<!-- Style for Header ******************************************************-->
+
<style name="card.header_outer_layout">
<item name="android:layout_marginTop">@dimen/card_header_outer_view_margin_top</item>
<item name="android:layout_marginBottom">@dimen/card_header_outer_view_margin_bottom</item>
- <item name="android:layout_marginStart">@dimen/card_header_outer_view_margin_start</item>
- <item name="android:layout_marginEnd">@dimen/card_header_outer_view_margin_end</item>
+ <item name="android:layout_marginLeft">@dimen/card_header_outer_view_margin_left</item>
+ <item name="android:layout_marginRight">@dimen/card_header_outer_view_margin_right</item>
+ </style>
+
+ <style name="card.native.header_outer_layout" >
+ <item name="android:paddingLeft">@dimen/card_header_native_default_paddingLeft</item>
+ <item name="android:paddingRight">@dimen/card_header_native_default_paddingRight</item>
+ <item name="android:paddingTop">@dimen/card_header_native_default_paddingTop</item>
+ <item name="android:paddingBottom">@dimen/card_header_native_default_paddingBottom</item>
+ </style>
+
+ <style name="card.native.header_outer_layout.nomargin" >
+ <item name="android:paddingLeft">0dp</item>
+ <item name="android:paddingRight">0dp</item>
+ <item name="android:paddingTop">0dp</item>
+ <item name="android:paddingBottom">0dp</item>
</style>
<!--Style for Header Compound View -->
@@ -54,43 +80,82 @@
</style>
- <!--Style for simple title header inner view-->
+ <style name="card.native.header_compound_view">
+
+ </style>
+
+ <style name="card.native.header_inner_frame">
+ <item name="android:layout_centerVertical">true</item>
+ </style>
+
+ <!--Style for simple title inner header view-->
<style name="card.header_simple_title">
- <item name="android:layout_width">wrap_content</item>
- <item name="android:layout_height">wrap_content</item>
- <item name="android:layout_gravity">start|center_vertical</item>
- <item name="android:fontFamily">sans-serif-condensed</item>
- <item name="android:textColor">@color/card_text_color_header</item>
<item name="android:textSize">@dimen/card_header_simple_title_text_size</item>
- <item name="android:layout_marginStart">@dimen/card_header_simple_title_margin_start</item>
+ <item name="android:textColor">@color/card_text_color_header</item>
+ <item name="android:layout_gravity">left|center_vertical</item>
+ <item name="android:layout_marginLeft">@dimen/card_header_simple_title_margin_left</item>
<item name="android:layout_marginTop">@dimen/card_header_simple_title_margin_top</item>
- <item name="android:layout_marginEnd">@dimen/card_header_simple_title_margin_end</item>
+ <item name="android:layout_marginRight">@dimen/card_header_simple_title_margin_right</item>
<item name="android:layout_marginBottom">@dimen/card_header_simple_title_margin_bottom</item>
</style>
+ <style name="card.native.header_simple_title" >
+ <item name="android:textSize">@dimen/card_header_native_simple_title_text_size</item>
+ <item name="android:textColor">@color/card_text_color_header</item>
+ <item name="android:layout_gravity">left|center_vertical</item>
+ <item name="android:layout_marginLeft">@dimen/card_header_native_simple_title_margin_left</item>
+ <item name="android:layout_marginTop">@dimen/card_header_native_simple_title_margin_top</item>
+ <item name="android:layout_marginRight">@dimen/card_header_native_simple_title_margin_right</item>
+ <item name="android:layout_marginBottom">@dimen/card_header_native_simple_title_margin_bottom</item>
+ </style>
+
<!-- Style for Header Buttons ***********************************************-->
<style name="card.header_button_frame">
</style>
+
+ <style name="card.native.header_button_frame">
+ <item name="android:layout_centerVertical">true</item>
+ <item name="android:layout_alignParentRight">true</item>
+ </style>
+
<!-- Button Base in Header-->
<style name="card.header_button_base">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
- <item name="android:layout_alignParentEnd">true</item>
- <item name="android:paddingStart">@dimen/card_header_button_padding_start</item>
+ <item name="android:layout_alignParentRight">true</item>
+ <item name="android:paddingLeft">@dimen/card_header_button_padding_left</item>
+ <item name="android:focusable">false</item>
+ <item name="android:focusableInTouchMode">false</item>
+ <item name="android:clickable">true</item>
+ <item name="android:layout_centerVertical">true</item>
+ <item name="android:layout_gravity">center_vertical</item>
+ <item name="android:layout_marginRight">@dimen/card_header_button_margin_right</item>
+ </style>
+
+ <style name="card.native.header_button_base">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_alignParentRight">true</item>
<item name="android:focusable">false</item>
<item name="android:focusableInTouchMode">false</item>
<item name="android:clickable">true</item>
<item name="android:layout_centerVertical">true</item>
- <item name="android:layout_marginEnd">@dimen/card_header_button_margin_end</item>
+ <item name="android:layout_gravity">center_vertical</item>
+ <item name="android:layout_marginLeft">@dimen/card_header_native_button_margin_left</item>
+ <item name="android:layout_marginRight">@dimen/card_header_native_button_margin_right</item>
+ <item name="android:paddingLeft">0dp</item>
</style>
<!-- Button Overflow in Header -->
<style name="card.header_button_base.overflow" >
<item name="android:background">@drawable/card_menu_button_rounded_overflow</item>
- <item name="android:layout_marginEnd">@dimen/card_header_button_overflow_margin_end</item>
+ </style>
+
+ <style name="card.native.header_button_base.overflow" >
+ <item name="android:background">@drawable/card_menu_button_overflow_material</item>
</style>
<!-- Button to Expand/Collapse in Header -->
@@ -98,11 +163,19 @@
<item name="android:background">@drawable/card_menu_button_expand</item>
</style>
+ <style name="card.native.header_button_base.expand">
+ <item name="android:background">@drawable/card_menu_button_expand_material_animator</item>
+ </style>
+
+
<!-- Other Button in Header -->
<style name="card.header_button_base.other">
</style>
+ <style name="card.native.header_button_base.other">
+
+ </style>
<!-- Style for Content ******************************************************-->
@@ -112,19 +185,38 @@
<item name="android:minHeight">@dimen/card_base_empty_height</item>
<item name="android:layout_marginTop">@dimen/card_content_outer_view_margin_top</item>
<item name="android:layout_marginBottom">@dimen/card_content_outer_view_margin_bottom</item>
- <item name="android:layout_marginStart">@dimen/card_content_outer_view_margin_start</item>
- <item name="android:layout_marginEnd">@dimen/card_content_outer_view_margin_end</item>
+ <item name="android:layout_marginLeft">@dimen/card_content_outer_view_margin_left</item>
+ <item name="android:layout_marginRight">@dimen/card_content_outer_view_margin_right</item>
+ </style>
+
+ <!--Style for Content View-->
+ <style name="card.native.content_outer_layout" >
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:minHeight">@dimen/card_base_empty_height</item>
+ <item name="android:paddingLeft">@dimen/card_main_content_native_default_paddingLeft</item>
+ <item name="android:paddingRight">@dimen/card_main_content_native_default_paddingRight</item>
+ <item name="android:paddingTop">@dimen/card_main_content_native_default_paddingTop</item>
+ <item name="android:paddingBottom">@dimen/card_main_content_native_default_paddingBottom</item>
</style>
<!--Style for simple title inner main view-->
<style name="card.base_simple_title">
<item name="android:textStyle">bold</item>
- <item name="android:fontFamily">sans-serif</item>
- <item name="android:layout_gravity">start|center_vertical</item>
- <item name="android:layout_marginStart">@dimen/card_main_simple_title_margin_start</item>
+ <item name="android:layout_gravity">left|center_vertical</item>
+ <item name="android:layout_marginLeft">@dimen/card_main_simple_title_margin_left</item>
<item name="android:layout_marginTop">@dimen/card_main_simple_title_margin_top</item>
+ <item name="android:layout_marginRight">@dimen/card_main_simple_title_margin_right</item>
+ <item name="android:layout_marginBottom">@dimen/card_main_simple_title_margin_bottom</item>
</style>
+ <!--Style for simple title inner main view-->
+ <style name="card.native.base_simple_title">
+ <item name="android:textStyle">bold</item>
+ <item name="android:textSize">@dimen/card_main_content_native_simple_title_text_size</item>
+ <item name="android:layout_gravity">left|center_vertical</item>
+ <item name="android:layout_marginLeft">@dimen/card_main_native_simple_title_margin_left</item>
+ <item name="android:layout_marginTop">@dimen/card_main_native_simple_title_margin_top</item>
+ </style>
<!-- Style for Main Layout ****************************************-->
@@ -133,8 +225,8 @@
<item name="android:background">@drawable/card_selector</item>
<item name="android:layout_marginTop">@dimen/card_main_layout_view_margin_top</item>
<item name="android:layout_marginBottom">@dimen/card_main_layout_view_margin_bottom</item>
- <item name="android:layout_marginStart">@dimen/card_main_layout_view_margin_start</item>
- <item name="android:layout_marginEnd">@dimen/card_main_layout_view_margin_end</item>
+ <item name="android:layout_marginLeft">@dimen/card_main_layout_view_margin_left</item>
+ <item name="android:layout_marginRight">@dimen/card_main_layout_view_margin_right</item>
</style>
<!-- Style for Main Layout kitkat-->
@@ -142,14 +234,22 @@
<item name="android:background">@drawable/card_kitkat_selector</item>
</style>
+ <style name="card.native.main_layout" >
+ <item name="android:background">?android:selectableItemBackground</item>
+ <item name="android:layout_marginTop">@dimen/card_main_layout_native_view_margin_top</item>
+ <item name="android:layout_marginBottom">@dimen/card_main_layout_native_view_margin_bottom</item>
+ <item name="android:layout_marginLeft">@dimen/card_main_layout_native_view_margin_left</item>
+ <item name="android:layout_marginRight">@dimen/card_main_layout_native_view_margin_right</item>
+ </style>
+
<!-- Style for Main Layout with foreground selector-->
<style name="card.main_layout_foreground">
<item name="android:background">@drawable/card_background</item>
<item name="android:foreground">@drawable/card_foreground_selector</item>
<item name="android:layout_marginTop">@dimen/card_main_layout_view_margin_top</item>
<item name="android:layout_marginBottom">@dimen/card_main_layout_view_margin_bottom</item>
- <item name="android:layout_marginStart">@dimen/card_main_layout_view_margin_start</item>
- <item name="android:layout_marginEnd">@dimen/card_main_layout_view_margin_end</item>
+ <item name="android:layout_marginLeft">@dimen/card_main_layout_view_margin_left</item>
+ <item name="android:layout_marginRight">@dimen/card_main_layout_view_margin_right</item>
</style>
<!-- Style for Main Layout with foreground selector kitkat-->
@@ -157,6 +257,14 @@
<item name="android:foreground">@drawable/card_foreground_kitkat_selector</item>
</style>
+ <style name="card.native.main_layout_foreground">
+ <item name="android:foreground">?android:selectableItemBackground</item>
+ <item name="android:background">@color/card_native_background</item>
+ <item name="android:layout_marginTop">@dimen/card_main_layout_native_view_margin_top</item>
+ <item name="android:layout_marginBottom">@dimen/card_main_layout_native_view_margin_bottom</item>
+ <item name="android:layout_marginLeft">@dimen/card_main_layout_native_view_margin_left</item>
+ <item name="android:layout_marginRight">@dimen/card_main_layout_native_view_margin_right</item>
+ </style>
<!-- Style for Hidden Expand Layout ****************************************-->
@@ -165,18 +273,35 @@
<item name="android:padding">@dimen/card_expand_layout_padding</item>
</style>
+ <style name="card.native.main_contentExpand" >
+ <item name="android:background">@color/card_backgroundExpand</item>
+ <item name="android:layout_marginLeft">@dimen/card_expand_native_margin_right</item>
+ <item name="android:layout_marginRight">@dimen/card_expand_native_margin_right</item>
+ <item name="android:paddingLeft">@dimen/card_expand_native_layout_padding_left</item>
+ <item name="android:paddingRight">@dimen/card_expand_native_layout_padding_right</item>
+ <item name="android:paddingTop">@dimen/card_expand_native_layout_padding_top</item>
+ <item name="android:paddingBottom">@dimen/card_expand_native_layout_padding_bottom</item>
+ </style>
<!--Style for simple title expand/collapse inner view-->
<style name="card.expand_simple_title">
- <item name="android:layout_gravity">start|center_vertical</item>
+ <item name="android:layout_gravity">left|center_vertical</item>
<item name="android:gravity">center_vertical</item>
- <item name="android:fontFamily">sans-serif-condensed</item>
<item name="android:textSize">@dimen/card_expand_simple_title_text_size</item>
- <item name="android:paddingStart">@dimen/card_expand_simple_title_paddingStart</item>
- <item name="android:paddingEnd">@dimen/card_expand_simple_title_paddingEnd</item>
+ <item name="android:paddingLeft">@dimen/card_expand_simple_title_paddingLeft</item>
+ <item name="android:paddingRight">@dimen/card_expand_simple_title_paddingRight</item>
<item name="android:textColor">@color/card_expand_title_color</item>
</style>
+ <!--Style for simple title expand/collapse inner view-->
+ <style name="card.native.expand_simple_title">
+ <item name="android:layout_gravity">left|center_vertical</item>
+ <item name="android:gravity">center_vertical</item>
+ <item name="android:textSize">@dimen/card_expand_native_simple_title_text_size</item>
+ <item name="android:paddingLeft">@dimen/card_expand_native_simple_title_padding_left</item>
+ <item name="android:paddingRight">@dimen/card_expand_native_simple_title_padding_right</item>
+ <item name="android:textColor">@color/card_expand_title_color</item>
+ </style>
<!-- Style for Thumbnail ******************************************************-->
@@ -195,12 +320,39 @@
<style name="card.thumbnail_compound_view"></style>
+ <style name="card.native.card_thumbnail_image">
+ <item name="android:layout_width">@dimen/card_thumbnail_width</item>
+ <item name="android:layout_height">@dimen/card_thumbnail_height</item>
+ <item name="android:layout_gravity">center</item>
+ <item name="android:gravity">center</item>
+ <item name="android:scaleType">centerCrop</item>
+ </style>
+
+ <style name="card.native.card_thumbnail_outer_layout">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ </style>
+
+ <style name="card.native.thumbnail_compound_view">
+
+ </style>
+
+ <!-- CardWithList ******************************************************-->
+
+ <!--Style for Content View-->
+ <style name="card.native.content_outer_layout.cardwithlist" >
+ <item name="android:paddingLeft">@dimen/card_main_content_native_cardwithlist_paddingLeft</item>
+ <item name="android:paddingRight">@dimen/card_main_content_native_cardwithlist_paddingRight</item>
+ <item name="android:paddingTop">@dimen/card_main_content_native_cardwithlist_paddingTop</item>
+ <item name="android:paddingBottom">@dimen/card_main_content_native_cardwithlist_paddingBottom</item>
+ </style>
+
<!-- Style for Lists ******************************************************-->
<style name="list_card">
- <item name="android:paddingStart">@dimen/list_card_padding_start</item>
- <item name="android:paddingEnd">@dimen/list_card_padding_end</item>
+ <item name="android:paddingLeft">@dimen/list_card_padding_left</item>
+ <item name="android:paddingRight">@dimen/list_card_padding_right</item>
<item name="android:paddingBottom">@dimen/list_card_padding_bottom</item>
<item name="android:paddingTop">@dimen/list_card_padding_top</item>
</style>
@@ -216,11 +368,92 @@
</style>
+
+ <style name="native_list_external">
+ <item name="android:clipToPadding">false</item>
+ <item name="android:scrollbarStyle">outsideOverlay</item>
+ </style>
+
+ <style name="native_list_card">
+ <item name="android:layout_marginLeft">@dimen/native_list_card_margin_left</item>
+ <item name="android:layout_marginRight">@dimen/native_list_card_margin_right</item>
+ <item name="android:layout_marginBottom">@dimen/native_list_card_margin_bottom</item>
+ <item name="android:layout_marginTop">@dimen/native_list_card_margin_top</item>
+ </style>
+
+ <!-- Base list -->
+ <style name="native_list_card.base" >
+
+ </style>
+
+
+ <!-- Thumbnail list -->
+ <style name="native_list_card.thumbnail">
+
+ </style>
+
+
+
+
+
<style name="grid_card">
- <item name="android:paddingStart">@dimen/grid_card_padding_start</item>
- <item name="android:paddingEnd">@dimen/grid_card_padding_end</item>
+ <item name="android:paddingLeft">@dimen/grid_card_padding_left</item>
+ <item name="android:paddingRight">@dimen/grid_card_padding_right</item>
+ <item name="android:paddingBottom">@dimen/grid_card_padding_bottom</item>
+ <item name="android:paddingTop">@dimen/grid_card_padding_top</item>
+ </style>
+
+ <style name="native_grid_card">
+ <item name="android:paddingLeft">@dimen/grid_card_padding_left</item>
+ <item name="android:paddingRight">@dimen/grid_card_padding_right</item>
<item name="android:paddingBottom">@dimen/grid_card_padding_bottom</item>
<item name="android:paddingTop">@dimen/grid_card_padding_top</item>
</style>
+ <!-- Style for card with list -->
+ <style name="cardwithlist">
+ <item name="android:layout_marginTop">@dimen/card_base_cardwithlist_list_margin_top</item>
+ <item name="android:layout_marginLeft">@dimen/card_base_cardwithlist_list_margin_left</item>
+ <item name="android:divider">@color/card_base_cardwithlist_divider_color</item>
+ <item name="android:showDividers">middle|beginning</item>
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">match_parent</item>
+ <item name="android:background">@color/card_base_cardwithlist_background_list_color</item>
+ </style>
+
+ <style name="native_cardwithlist">
+ <item name="android:layout_marginTop">@dimen/card_base_cardwithlist_list_margin_top</item>
+ <item name="android:layout_marginLeft">@dimen/card_base_cardwithlist_list_margin_left</item>
+ <item name="android:divider">@color/card_native_base_cardwithlist_divider_color</item>
+ <item name="android:showDividers">middle|beginning</item>
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">match_parent</item>
+ <item name="android:background">@color/card_native_base_cardwithlist_background_list_color</item>
+ </style>
+
+
+ <!-- Style used for Sectioned List -->
+ <style name="card_section_container">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:paddingLeft">@dimen/card_section_container_padding_left</item>
+ <item name="android:paddingRight">@dimen/card_section_container_padding_right</item>
+ <item name="android:background">@color/card_section_container_color</item>
+ </style>
+
+ <style name="card_section_title">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_alignParentLeft">true</item>
+ <item name="android:textSize">@dimen/card_section_title</item>
+ <item name="android:textColor">@color/card_section_title_color</item>
+ <item name="android:layout_gravity">center_vertical</item>
+ <item name="android:layout_centerVertical">true</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:layout_marginTop">@dimen/card_section_title_margin_top</item>
+ <item name="android:layout_marginBottom">@dimen/card_section_title_margin_top</item>
+ </style>
+
+
+
</resources>
diff --git a/res/values/styles_undo.xml b/res/values/styles_undo.xml
index b52f5c3..ff5c98d 100644
--- a/res/values/styles_undo.xml
+++ b/res/values/styles_undo.xml
@@ -24,8 +24,8 @@
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">48dp</item>
<item name="android:layout_gravity">bottom</item>
- <item name="android:layout_marginStart">8dp</item>
- <item name="android:layout_marginEnd">8dp</item>
+ <item name="android:layout_marginLeft">8dp</item>
+ <item name="android:layout_marginRight">8dp</item>
<item name="android:layout_marginBottom">16dp</item>
<item name="android:orientation">horizontal</item>
<item name="android:background">@drawable/undobar</item>
@@ -39,9 +39,9 @@
<item name="android:layout_width">0dp</item>
<item name="android:layout_weight">1</item>
<item name="android:layout_height">wrap_content</item>
- <item name="android:layout_marginStart">16dp</item>
+ <item name="android:layout_marginLeft">16dp</item>
<item name="android:layout_gravity">center_vertical</item>
- <item name="android:layout_marginEnd">16dp</item>
+ <item name="android:layout_marginRight">16dp</item>
<item name="android:textAppearance">?android:textAppearanceSmall</item>
<item name="android:textColor">#fff</item>
@@ -50,10 +50,10 @@
<style name="list_card_UndoBarButton">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">match_parent</item>
- <item name="android:paddingStart">16dp</item>
- <item name="android:paddingEnd">16dp</item>
+ <item name="android:paddingLeft">16dp</item>
+ <item name="android:paddingRight">16dp</item>
<item name="android:background">@drawable/card_undo</item>
- <item name="android:drawableStart">@drawable/ic_undobar_undo</item>
+ <item name="android:drawableLeft">@drawable/ic_undobar_undo</item>
<item name="android:drawablePadding">12dp</item>
<item name="android:textAppearance">?android:textAppearanceSmall</item>
<item name="android:textAllCaps">true</item>
@@ -62,4 +62,90 @@
<item name="android:text">@string/list_card_undo_title</item>
</style>
-</resources>
+ <style name="list_card_UndoBar_material">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">56dp</item>
+ <item name="android:layout_gravity">bottom</item>
+ <item name="android:layout_marginLeft">32dp</item>
+ <item name="android:layout_marginRight">32dp</item>
+ <item name="android:layout_marginBottom">24dp</item>
+ <item name="android:paddingBottom">18dp</item>
+ <item name="android:paddingTop">18dp</item>
+ <item name="android:paddingLeft">24dp</item>
+ <item name="android:paddingRight">24dp</item>
+ <item name="android:orientation">horizontal</item>
+ <item name="android:background">@color/card_undobar_material_background_color</item>
+ <item name="android:clickable">true</item>
+ </style>
+
+ <style name="list_card_UndoBarMessage_material">
+ <item name="android:layout_width">0dp</item>
+ <item name="android:layout_weight">1</item>
+ <item name="android:layout_height">match_parent</item>
+ <item name="android:layout_gravity">center_vertical</item>
+ <item name="android:layout_marginLeft">0dp</item>
+ <item name="android:layout_marginRight">24dp</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">#fff</item>
+ </style>
+
+ <style name="list_card_UndoBarButton_material">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">match_parent</item>
+ <item name="android:gravity">right</item>
+ <item name="android:background">?android:selectableItemBackground</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:paddingLeft">24dp</item>
+ <item name="android:textAllCaps">true</item>
+ <item name="android:textStyle">bold</item>
+ <item name="android:textColor">@color/card_undobar_material_text_color</item>
+ <item name="android:text">@string/list_card_undo_title</item>
+ </style>
+
+ <style name="list_card_UndoBar_materialmobile">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:minHeight">56dp</item>
+ <item name="android:maxHeight">80dp</item>
+ <item name="android:layout_gravity">bottom</item>
+ <item name="android:layout_marginLeft">0dp</item>
+ <item name="android:layout_marginRight">0dp</item>
+ <item name="android:layout_marginBottom">0dp</item>
+ <item name="android:paddingLeft">24dp</item>
+ <item name="android:paddingRight">0dp</item>
+ <item name="android:orientation">horizontal</item>
+ <item name="android:background">@color/card_undobar_material_background_color</item>
+ <item name="android:clickable">true</item>
+ </style>
+
+ <style name="list_card_UndoBarMessage_materialmobile">
+ <item name="android:layout_width">0dp</item>
+ <item name="android:layout_weight">1</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_gravity">center_vertical</item>
+ <item name="android:layout_marginLeft">0dp</item>
+ <item name="android:layout_marginRight">24dp</item>
+ <item name="android:layout_marginBottom">18dp</item>
+ <item name="android:layout_marginTop">18dp</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">#fff</item>
+ </style>
+
+ <style name="list_card_UndoBarButton_materialmobile">
+ <item name="android:layout_gravity">center_vertical|right</item>
+ <item name="android:gravity">right</item>
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:paddingBottom">18dp</item>
+ <item name="android:paddingTop">18dp</item>
+ <item name="android:paddingLeft">24dp</item>
+ <item name="android:paddingRight">24dp</item>
+ <item name="android:background">?android:selectableItemBackground</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:textAllCaps">true</item>
+ <item name="android:textStyle">bold</item>
+ <item name="android:textColor">@color/card_undobar_material_text_color</item>
+ <item name="android:text">@string/list_card_undo_title</item>
+ </style>
+
+</resources> \ No newline at end of file
diff --git a/src/com/android/cards/internal/overflowanimation/BaseCardOverlayAnimation.java b/src/com/android/cards/internal/overflowanimation/BaseCardOverlayAnimation.java
deleted file mode 100644
index 99b5760..0000000
--- a/src/com/android/cards/internal/overflowanimation/BaseCardOverlayAnimation.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * ******************************************************************************
- * Copyright (c) 2013-2014 Gabriele Mariotti.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * *****************************************************************************
- */
-
-package com.android.cards.internal.overflowanimation;
-
-import android.content.Context;
-import android.view.View;
-
-import com.android.cards.R;
-import com.android.cards.internal.Card;
-
-/**
- * BaseAnimation to overlay the Card
- *
- * @author Gabriele Mariotti (gabri.mariotti@gmail.com)
- */
-public abstract class BaseCardOverlayAnimation extends BaseOverflowAnimation {
-
- /**
- * Original card
- */
- protected Card originalCard;
-
- /**
- * Animation Duration
- */
- protected int mAnimationDuration;
-
- // -------------------------------------------------------------
- // Constructors
- // -------------------------------------------------------------
-
- public BaseCardOverlayAnimation(Context context, Card card) {
- super(context);
- this.originalCard = card;
- }
-
- // -------------------------------------------------------------
- // CardInfoToAnimate model
- // -------------------------------------------------------------
-
- /**
- * Public interface for Card Animation
- */
- public interface CardInfo {
- /**
- *
- * @param layoutId
- */
- public void setupLayoutsIdToRemove(int[] layoutId);
-
- /**
- *
- */
- public int[] getLayoutsIdToAdd();
- }
-
- /**
- * CardInfo provides info about layouts to remove, and layouts to add
- */
- public abstract class CardInfoToAnimate implements CardInfo {
-
- /*
- * Layouts to Remove
- */
- protected int[] mLayoutsIdToRemove;
-
- // -----------------------------
- // Constructors
- // -----------------------------
-
- public CardInfoToAnimate() {
- defaultIdToRemove();
- }
-
- /**
- * Default layouts to remove
- */
- private void defaultIdToRemove(){
- mLayoutsIdToRemove = new int[]
- {
- R.id.card_header_inner_frame,
- R.id.card_thumbnail_layout,
- R.id.card_main_content_layout
- };
- }
-
- @Override
- public void setupLayoutsIdToRemove(int[] layoutId) {
- this.mLayoutsIdToRemove=layoutId;
- }
-
- @Override
- public abstract int[] getLayoutsIdToAdd();
-
- /**
- * Indicates if card need a navigator
- *
- * @return
- */
- protected boolean isWithNavigator(){
- if (getLayoutsIdToAdd()!=null && getLayoutsIdToAdd().length>1)
- return true;
- else
- return false;
- }
- }
-
- protected abstract CardInfoToAnimate setCardToAnimate(Card card);
-
- // -------------------------------------------------------------
- // Animation
- // -------------------------------------------------------------
-
- @Override
- public void doAnimation(final Card card, View imageOverflow) {
- //Store selected values
- super.doAnimation(card, imageOverflow);
-
- if (card == null || card.getCardView() == null) return;
-
- //animation duration
- //final int mShortAnimationDuration = getAnimationDuration();
-
- final CardInfoToAnimate infoAnimation = setCardToAnimate(card);
-
- if (infoAnimation == null) return;
-
- if (!selected) {
- doOverFirstAnimation(card,infoAnimation, imageOverflow);
- } else {
- //TODO More Cards
- doOverOtherAnimation(card,infoAnimation, imageOverflow);
- }
-
- //Update icon and model status
- toggleOverflowIcon();
- }
-
- protected abstract void doOverOtherAnimation(Card card,CardInfoToAnimate infoAnimation,View imageOverflow);
-
- protected abstract void doOverFirstAnimation(Card card,CardInfoToAnimate infoAnimation,View imageOverflow);
-
-
- // -------------------------------------------------------------
- // Getters and Setters
- // -------------------------------------------------------------
-
- /**
- * Returns the animation duration
- *
- * @return
- */
- protected int getAnimationDuration() {
- return mAnimationDuration = mContext.getResources().getInteger(
- android.R.integer.config_shortAnimTime);
- }
-
-
-}
diff --git a/src/com/android/cards/internal/overflowanimation/BaseOverflowAnimation.java b/src/com/android/cards/internal/overflowanimation/BaseOverflowAnimation.java
deleted file mode 100644
index 93757be..0000000
--- a/src/com/android/cards/internal/overflowanimation/BaseOverflowAnimation.java
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * ******************************************************************************
- * Copyright (c) 2013-2014 Gabriele Mariotti.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * *****************************************************************************
- */
-
-package com.android.cards.internal.overflowanimation;
-
-import android.content.Context;
-import android.view.View;
-
-import com.android.cards.internal.Card;
-import com.android.cards.internal.CardHeader;
-import com.android.cards.view.CardView;
-
-/**
- * Base implementation of CustomOverflowAnimator
- * This class helps to store the card and the selected value on overflow icon
- *
- * @author Gabriele Mariotti (gabri.mariotti@gmail.com)
- */
-public abstract class BaseOverflowAnimation implements CardHeader.CustomOverflowAnimation{
-
- /**
- * Context
- */
- protected Context mContext;
-
- /**
- * Overflow icon state
- */
- protected boolean selected=false;
-
- /**
- * Card
- */
- private Card mCard;
-
- protected static String TAG="BaseOverflowAnimation";
-
- // -------------------------------------------------------------
- // Constructors
- // -------------------------------------------------------------
-
- public BaseOverflowAnimation(Context context){
- mContext=context;
- }
-
- // -------------------------------------------------------------
- // Base Animation
- // -------------------------------------------------------------
-
- @Override
- public void doAnimation(Card card, View imageOverflow) {
-
- //Store the Card
- if (card==null) return;
- mCard=card;
-
- //Get the selected value from the Header
- CardHeader header= card.getCardHeader();
- if (header!=null){
- selected=header.isOverflowSelected();
- }
- }
-
- // -------------------------------------------------------------
- // Select and deselect the overflow icon
- // -------------------------------------------------------------
-
- /**
- * Selects overflow icon
- */
- protected void selectOverflowIcon(){
- changeOverflowIconSelection(true);
- }
-
- /**
- * Deselects overflow icon
- */
- protected void deselectOverflowIcon(){
- changeOverflowIconSelection(false);
- }
-
- /**
- * Toggles the overflow icon
- */
- protected void toggleOverflowIcon(){
-
- if (mCard==null) return;
- changeOverflowIconSelection(!selected);
- }
-
- /**
- * Internal method to change the state of overflow icon on the view and on the model
- *
- * @param selected
- */
- protected void changeOverflowIconSelection(boolean selected){
-
- if (mCard==null) return;
-
- //Change the value on the card and inside
- CardHeader header = mCard.getCardHeader();
- if (header!=null){
- this.selected=selected;
- header.setOverflowSelected(selected);
- }
-
- //Change the imageButton state
- CardView cardView = mCard.getCardView();
- if (cardView!=null){
- if (cardView.getInternalHeaderLayout()!=null && cardView.getInternalHeaderLayout().getImageButtonOverflow()!=null)
- cardView.getInternalHeaderLayout().getImageButtonOverflow().setSelected(selected);
- }
- }
-
-
- // -------------------------------------------------------------
- // Getters and Setters
- // -------------------------------------------------------------
-
- /**
- * Return the context
- *
- * @return
- */
- protected Context getContext() {
- return mContext;
- }
-
- /**
- * Returns the overflow icon state
- * @return
- */
- public boolean isSelected() {
- return selected;
- }
-
- /**
- * Sets the overflow icon state
- * @param selected
- */
- public void setSelected(boolean selected) {
- this.selected = selected;
- }
-
- /**
- * Returns the card
- * @return
- */
- public Card getCard() {
- return mCard;
- }
-
-}
diff --git a/src/com/android/cards/internal/overflowanimation/TwoCardOverlayAnimation.java b/src/com/android/cards/internal/overflowanimation/TwoCardOverlayAnimation.java
deleted file mode 100644
index 26fa2ae..0000000
--- a/src/com/android/cards/internal/overflowanimation/TwoCardOverlayAnimation.java
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * ******************************************************************************
- * Copyright (c) 2013-2014 Gabriele Mariotti.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * *****************************************************************************
- */
-
-package com.android.cards.internal.overflowanimation;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import java.util.ArrayList;
-
-import com.android.cards.R;
-import com.android.cards.internal.Card;
-
-/**
- * Simple implementation with only 2 card (the original and the overlay)
- *
- * @author Gabriele Mariotti (gabri.mariotti@gmail.com)
- */
-public abstract class TwoCardOverlayAnimation extends BaseCardOverlayAnimation {
-
- // -------------------------------------------------------------
- // Constructors
- // -------------------------------------------------------------
-
- public TwoCardOverlayAnimation(Context context, Card card) {
- super(context,card);
- }
-
- /**
- *
- */
- public abstract class TwoCardToAnimate extends CardInfoToAnimate{
-
- @Override
- public int[] getLayoutsIdToAdd() {
- int[] layouts= new int[1];
- layouts[0]=getLayoutIdToAdd();
- return layouts;
- }
-
- public abstract int getLayoutIdToAdd();
-
- }
-
-
- // -------------------------------------------------------------
- // Animation
- // -------------------------------------------------------------
-
-
- @Override
- protected void doOverFirstAnimation(final Card card, CardInfoToAnimate infoAnimation, View imageOverflow) {
-
- if (infoAnimation==null) return;
-
- final ViewGroup mInternalLayoutOverlay = (ViewGroup)card.getCardView().findViewById(R.id.card_overlap);
-
- //Checks
- if (mInternalLayoutOverlay==null){
- Log.e(TAG, "Overlap layout not found!");
- return;
- }
- if (infoAnimation.getLayoutsIdToAdd()==null){
- Log.e(TAG,"You have to specify layouts to add!");
- return;
- }
-
- //Views to remove
- View[] viewsOut= getOutViews(card,infoAnimation);
-
- //Get the layout to add
- final int layoutIdIn= infoAnimation.getLayoutsIdToAdd()[0];
-
- AnimatorSet animAlpha = new AnimatorSet();
- if (viewsOut != null && layoutIdIn > 0) {
-
- ArrayList<Animator> animators= new ArrayList<Animator>();
-
- for (final View viewOut:viewsOut){
- if (viewOut!=null){
- ObjectAnimator anim = ObjectAnimator.ofFloat(viewOut, "alpha", 1f, 0f);
- anim.setDuration(getAnimationDuration());
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- viewOut.setVisibility(View.GONE);
- }
- });
- animators.add(anim);
- }
- }
- animAlpha.playTogether(animators);
- }
-
-
- animAlpha.addListener(new AnimatorListenerAdapter(){
-
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
-
- LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- View viewIn= inflater.inflate(layoutIdIn,mInternalLayoutOverlay,false);
- if (viewIn!=null){
-
- if (card.getCardView()!=null &&
- card.getCardView().getInternalMainCardLayout()!=null &&
- card.getCardView().getInternalHeaderLayout()!=null &&
- card.getCardView().getInternalHeaderLayout().getFrameButton()!=null){
- int h1=card.getCardView().getInternalMainCardLayout().getMeasuredHeight();
- int h2=card.getCardView().getInternalHeaderLayout().getFrameButton().getMeasuredHeight();
- viewIn.setMinimumHeight(h1-h2);
- }
- mInternalLayoutOverlay.addView(viewIn);
-
- viewIn.setAlpha(0);
- viewIn.setVisibility(View.VISIBLE);
-
- viewIn.animate()
- .alpha(1f)
- .setDuration(getAnimationDuration())
- .setListener(null);
- }
- }
- });
-
- animAlpha.start();
- }
-
- @Override
- protected void doOverOtherAnimation(final Card card, CardInfoToAnimate infoAnimation, View imageOverflow) {
-
- //Checks
- if (infoAnimation == null) return;
-
- final ViewGroup mInternalLayoutOverlay = (ViewGroup) card.getCardView().findViewById(R.id.card_overlap);
- if (mInternalLayoutOverlay == null) {
- Log.e(TAG, "Overlap layout not found!");
- return;
- }
- if (infoAnimation.getLayoutsIdToAdd() == null) {
- Log.e(TAG, "You have to specify layouts to add!");
- return;
- }
-
- final View[] viewsLastOut = getOutViews(card, infoAnimation);
-
- //int layoutIdIn= infoAnimation.getLayoutsIdToAdd()[0];
- final View viewLastIn = mInternalLayoutOverlay.getChildAt(0);
- //final View viewIn = card.getCardView().findViewById(R.id.afterContent);
-
- //Views to remove
- final View[] viewsFirstOut = getOutViews(card, infoAnimation);
-
- if (viewLastIn != null) {
- viewLastIn.animate()
- .alpha(0f)
- .setDuration(getAnimationDuration())
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- viewLastIn.setVisibility(View.GONE);
-
-
- for (final View viewOut : viewsLastOut) {
- if (viewOut != null) {
- viewOut.setVisibility(View.VISIBLE);
- }
- }
-
- if (mInternalLayoutOverlay != null) {
- mInternalLayoutOverlay.removeView(viewLastIn);
- }
-
- for (final View viewOut : viewsLastOut) {
- if (viewOut != null) {
- viewOut.animate()
- .alpha(1f)
- .setDuration(getAnimationDuration());
- }
- }
-
- }
- });
- }
- }
-
- protected View[] getOutViews(Card card,CardInfoToAnimate infoAnimation){
- //Views to remove
- View[] viewsOut=null;
- if (infoAnimation.mLayoutsIdToRemove!=null){
-
- viewsOut = new View[infoAnimation.mLayoutsIdToRemove.length];
- int i=0;
- for (int layoutIdOut:infoAnimation.mLayoutsIdToRemove){
- View viewOut =card.getCardView().findViewById(layoutIdOut);
- viewsOut[i]=viewOut;
- i++;
- }
- }
- return viewsOut;
- }
-
-
- // -------------------------------------------------------------
- // Getters and Setters
- // -------------------------------------------------------------
-
- /**
- * Returns the animation duration
- *
- * @return
- */
- protected int getAnimationDuration() {
- return mAnimationDuration = mContext.getResources().getInteger(
- android.R.integer.config_shortAnimTime);
- }
-
-
-}
diff --git a/src/com/android/cards/view/listener/UndoBarController.java b/src/com/android/cards/view/listener/UndoBarController.java
deleted file mode 100644
index 2c5318c..0000000
--- a/src/com/android/cards/view/listener/UndoBarController.java
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * ******************************************************************************
- * Copyright (c) 2013 Roman Nurik, 2013-2014 Gabriele Mariotti.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * *****************************************************************************
- */
-
-package com.android.cards.view.listener;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Parcelable;
-import android.text.TextUtils;
-import android.view.View;
-import android.view.ViewPropertyAnimator;
-import android.widget.TextView;
-
-import com.android.cards.R;
-
-/**
- * It is based on Roman Nurik code.
- * See this link for original code:
- * https://code.google.com/p/romannurik-code/source/browse/#git%2Fmisc%2Fundobar
- *
- *
- */
-public class UndoBarController {
-
- private View mBarView;
- private TextView mMessageView;
- private ViewPropertyAnimator mBarAnimator;
- private Handler mHideHandler = new Handler();
-
- private UndoListener mUndoListener;
-
- // State objects
- private Parcelable mUndoToken;
- private CharSequence mUndoMessage;
-
- private UndoBarUIElements mUndoBarUIElements;
-
- /**
- * Interface to listen the undo controller actions
- */
- public interface UndoListener {
- /*
- * Called when you undo the action
- */
- void onUndo(Parcelable undoToken);
- }
-
- public UndoBarController(View undoBarView, UndoListener undoListener) {
- this (undoBarView,undoListener,null);
- }
-
- public UndoBarController(View undoBarView, UndoListener undoListener,UndoBarUIElements undoBarUIElements) {
- mBarView = undoBarView;
- mBarAnimator = mBarView.animate();
- mUndoListener = undoListener;
-
- if (undoBarUIElements==null)
- undoBarUIElements = new DefaultUndoBarUIElements();
- mUndoBarUIElements = undoBarUIElements;
-
- mMessageView = (TextView) mBarView.findViewById(mUndoBarUIElements.getUndoBarMessageId());
- mBarView.findViewById(mUndoBarUIElements.getUndoBarButtonId())
- .setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- hideUndoBar(false);
- mUndoListener.onUndo(mUndoToken);
- }
- });
-
- hideUndoBar(true);
- }
-
- public void showUndoBar(boolean immediate, CharSequence message, Parcelable undoToken) {
-
- mUndoToken = undoToken;
- mUndoMessage = message;
- mMessageView.setText(mUndoMessage);
-
- mHideHandler.removeCallbacks(mHideRunnable);
- mHideHandler.postDelayed(mHideRunnable,
- mBarView.getResources().getInteger(R.integer.list_card_undobar_hide_delay));
-
- mBarView.setVisibility(View.VISIBLE);
- if (immediate) {
- mBarView.setAlpha(1);
- } else {
- mBarAnimator.cancel();
- mBarAnimator
- .alpha(1)
- .setDuration(
- mBarView.getResources()
- .getInteger(android.R.integer.config_shortAnimTime))
- .setListener(null);
- }
- }
-
- public void hideUndoBar(boolean immediate) {
- mHideHandler.removeCallbacks(mHideRunnable);
- if (immediate) {
- mBarView.setVisibility(View.GONE);
- mBarView.setAlpha(0);
- mUndoMessage = null;
- mUndoToken = null;
-
- } else {
- mBarAnimator.cancel();
- mBarAnimator
- .alpha(0)
- .setDuration(mBarView.getResources()
- .getInteger(android.R.integer.config_shortAnimTime))
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mBarView.setVisibility(View.GONE);
- mUndoMessage = null;
- mUndoToken = null;
- }
- });
- }
- }
-
- public void onSaveInstanceState(Bundle outState) {
- outState.putCharSequence("undo_message", mUndoMessage);
- outState.putParcelable("undo_token", mUndoToken);
- }
-
- public void onRestoreInstanceState(Bundle savedInstanceState) {
- if (savedInstanceState != null) {
- mUndoMessage = savedInstanceState.getCharSequence("undo_message");
- mUndoToken = savedInstanceState.getParcelable("undo_token");
-
- if (mUndoToken != null || !TextUtils.isEmpty(mUndoMessage)) {
- showUndoBar(true, mUndoMessage, mUndoToken);
- }
- }
- }
-
- private Runnable mHideRunnable = new Runnable() {
- @Override
- public void run() {
- hideUndoBar(false);
- }
- };
-
- public Parcelable getUndoToken(){
- return mUndoToken;
- }
-
-
- // -------------------------------------------------------------
- // Undo Custom Bar
- // -------------------------------------------------------------
-
- /**
- * Interface to set the ui elements in undo bar
- */
- public interface UndoBarUIElements{
-
- /**
- * UndoBar id
- * @return
- */
- public int getUndoBarId();
-
- /**
- * TextView Id which displays message
- *
- * @return
- */
- public int getUndoBarMessageId();
-
- /**
- * UndoButton Id
- *
- * @return
- */
- public int getUndoBarButtonId();
-
-
- }
-
- /**
- * Default UndoBar
- */
- public static class DefaultUndoBarUIElements implements UndoBarUIElements {
-
- public DefaultUndoBarUIElements(){};
-
- @Override
- public int getUndoBarId() {
- return R.id.list_card_undobar;
- }
-
- @Override
- public int getUndoBarMessageId() {
- return R.id.list_card_undobar_message;
- }
-
- @Override
- public int getUndoBarButtonId() {
- return R.id.list_card_undobar_button;
- }
- };
-
-
- /**
- * Sets UndoBar UI Elements
- *
- * @return
- */
- public UndoBarUIElements getUndoBarUIElements() {
- return mUndoBarUIElements;
- }
-
- /**
- * Returns UndoBar UI Elements
- * @param undoBarUIElements
- */
- public void setUndoBarUIElements(UndoBarUIElements undoBarUIElements) {
- this.mUndoBarUIElements = undoBarUIElements;
- }
-}
diff --git a/src/com/android/cards/Constants.java b/src/it/gmariotti/cardslib/library/Constants.java
index cfe510d..65bc538 100644
--- a/src/com/android/cards/Constants.java
+++ b/src/it/gmariotti/cardslib/library/Constants.java
@@ -18,12 +18,16 @@
package com.android.cards;
+import android.os.Build;
+
/**
* @author Gabriele Mariotti (gabri.mariotti@gmail.com)
*/
public class Constants {
+ public static int API_L = Build.VERSION_CODES.LOLLIPOP;
+
public static class IntentManager{
/**
diff --git a/src/it/gmariotti/cardslib/library/internal/BaseGroupExpandableCard.java b/src/it/gmariotti/cardslib/library/internal/BaseGroupExpandableCard.java
new file mode 100644
index 0000000..8b6147b
--- /dev/null
+++ b/src/it/gmariotti/cardslib/library/internal/BaseGroupExpandableCard.java
@@ -0,0 +1,47 @@
+/*
+ * ******************************************************************************
+ * Copyright (c) 2013-2014 Gabriele Mariotti.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * *****************************************************************************
+ */
+
+package com.android.cards.internal;
+
+import android.content.Context;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Gabriele Mariotti (gabri.mariotti@gmail.com)
+ */
+public class BaseGroupExpandableCard<T> extends Card{
+
+ protected List<T> children = new ArrayList<T>();
+
+ //--------------------------------------------------------------------------
+ // Constructors
+ //--------------------------------------------------------------------------
+
+ public BaseGroupExpandableCard(Context context,List<T> children) {
+ super(context);
+ this.children = children;
+ }
+
+ public BaseGroupExpandableCard(Context context, int innerLayout,List<T> children) {
+ super(context, innerLayout);
+ this.children = children;
+ }
+
+}
diff --git a/src/com/android/cards/internal/Card.java b/src/it/gmariotti/cardslib/library/internal/Card.java
index 1d464f1..f3bdf52 100644
--- a/src/com/android/cards/internal/Card.java
+++ b/src/it/gmariotti/cardslib/library/internal/Card.java
@@ -60,6 +60,8 @@ public class Card extends BaseCard {
protected static String TAG = "Card";
+ public static int DEFAULT_COLOR= 0;
+
/**
* Used to enable a onClick Action on card
*/
@@ -125,14 +127,19 @@ public class Card extends BaseCard {
protected OnCollapseAnimatorEndListener mOnCollapseAnimatorEndListener;
/**
- * Partial OnClickListener
+ * Listener invoked when Expand Animator starts
*/
- protected HashMap<Integer, OnCardClickListener> mMultipleOnClickListener;
+ protected OnExpandAnimatorStartListener mOnExpandAnimatorStartListener;
+
+ /**
+ * Listener invoked when Collapse Animator starts
+ */
+ protected OnCollapseAnimatorStartListener mOnCollapseAnimatorStartListener;
/**
* Partial OnClickListener
*/
- protected HashMap<Integer, OnLongCardClickListener> mMultipleOnLongClickListener;
+ protected HashMap<Integer, OnCardClickListener> mMultipleOnClickListener;
/**
* Global area
@@ -153,27 +160,32 @@ public class Card extends BaseCard {
public static final int CLICK_LISTENER_HEADER_VIEW = 2;
/**
- * Expand Area
- * It is used by partial click listener
- */
- public static final int CLICK_LISTENER_EXPAND_VIEW = 3;
-
- /**
* Content Main area.
It is used by partial click listener
*/
public static final int CLICK_LISTENER_CONTENT_VIEW = 10;
/**
+ * All card area except the supplemental area with actions.
+ It is used by partial click listener
+ */
+ public static final int CLICK_LISTENER_ACTIONAREA1_VIEW = 9;
+
+ /**
* Listener invoked when the user undo a swipe action in a List
*/
protected OnUndoSwipeListListener mOnUndoSwipeListListener;
/**
+ * Listener invoked when the Undo controller hides the Undo Bar after a swipe action in a List
+ */
+ protected OnUndoHideSwipeListListener mOnUndoHideSwipeListListener;
+
+ /**
* It identifies the background resource of view with this id:
* android:id="@+id/card_main_layout"
* <p/>
- * In a standard card it identifies the main background.
+ * In a native card it identifies the main background.
*/
private int mBackgroundResourceId =0;
@@ -181,11 +193,17 @@ public class Card extends BaseCard {
* It identifies the background resource of view with this id:
* android:id="@+id/card_main_layout"
* <p/>
- * In a standard card it identifies the main background.
+ * In a native card it identifies the main background.
*/
private Drawable mBackgroundResource =null;
/**
+ * In a native card it identifies the main background color.
+ * Use it only with a NativeCard
+ */
+ private int mBackgroundColorResourceId =0;
+
+ /**
* Used to enable a onLongClick Action on multichoiceAdapter
*/
private boolean mCheckable= true;
@@ -200,6 +218,14 @@ public class Card extends BaseCard {
*/
protected ViewToClickToExpand viewToClickToExpand=null;
+ /**
+ * Custom Elevation
+ */
+ protected Float mCardElevation;
+
+
+ private boolean couldUseNativeInnerLayout = false;
+
// -------------------------------------------------------------
// Constructors
// -------------------------------------------------------------
@@ -223,6 +249,9 @@ public class Card extends BaseCard {
super(context);
mParentCard = null;
mInnerLayout = innerLayout;
+
+ if (innerLayout == R.layout.inner_base_main)
+ couldUseNativeInnerLayout = true;
}
// -------------------------------------------------------------
@@ -247,6 +276,9 @@ public class Card extends BaseCard {
@Override
public View getInnerView(Context context, ViewGroup parent) {
+ //Check if the default inner layout could be the native layout
+ setupInnerLayout();
+
View view = super.getInnerView(context, parent);
//This provides a simple implementation with a single title
@@ -269,7 +301,6 @@ public class Card extends BaseCard {
* This method sets values to header elements and customizes view.
* <p/>
* Override this method to set your elements inside InnerView.
- * If you use listviews it is recommend to user a Viewholder like here.
*
* @param parent parent view (Inner Frame)
* @param view Inner View
@@ -279,24 +310,19 @@ public class Card extends BaseCard {
//Add simple title to header
if (view != null) {
- ViewHolder holder;
- holder = (ViewHolder) view.getTag();
-
- if (holder == null) {
- holder = new ViewHolder();
- holder.titleView =
- (TextView) view.findViewById(R.id.card_main_inner_simple_title);
- view.setTag(holder);
- }
- if (holder.titleView != null) {
- holder.titleView.setText(mTitle);
- }
+ TextView mTitleView = (TextView) view.findViewById(R.id.card_main_inner_simple_title);
+ if (mTitleView != null)
+ mTitleView.setText(mTitle);
}
-
}
- static class ViewHolder {
- TextView titleView;
+ /**
+ * Setup the inner layout
+ */
+ protected void setupInnerLayout(){
+ //Check if the default inner layout could be the native layout
+ if (couldUseNativeInnerLayout && isNative())
+ mInnerLayout = R.layout.native_inner_base_main;
}
// -------------------------------------------------------------
@@ -374,6 +400,14 @@ public class Card extends BaseCard {
}
// -------------------------------------------------------------
+ // Supplemental Actions
+ // -------------------------------------------------------------
+
+ public void setupSupplementalActions() {
+ //Do Nothing
+ }
+
+ // -------------------------------------------------------------
// On Swipe Interface and Listener
// -------------------------------------------------------------
@@ -429,6 +463,13 @@ public class Card extends BaseCard {
}
/**
+ * Interface to listen for when the Undo controller hides the Undo Bar
+ */
+ public interface OnUndoHideSwipeListListener {
+ public void onUndoHideSwipe(Card card);
+ }
+
+ /**
* Called when user undo a swipe action
*/
public void onUndoSwipeListCard() {
@@ -455,6 +496,23 @@ public class Card extends BaseCard {
this.mOnUndoSwipeListListener = onUndoSwipeListListener;
}
+ /**
+ * Returns listener invoked the Undo controller hides the Undo Bar
+ *
+ * @return listener
+ */
+ public OnUndoHideSwipeListListener getOnUndoHideSwipeListListener() {
+ return mOnUndoHideSwipeListListener;
+ }
+
+ /**
+ * Sets listener invoked when the Undo controller hides the Undo Bar
+ *
+ * @param onUndoHideSwipeListListener
+ */
+ public void setOnUndoHideSwipeListListener(OnUndoHideSwipeListListener onUndoHideSwipeListListener) {
+ mOnUndoHideSwipeListListener = onUndoHideSwipeListListener;
+ }
// -------------------------------------------------------------
// OnClickListener
@@ -567,6 +625,40 @@ public class Card extends BaseCard {
this.mOnExpandAnimatorEndListener = onExpandAnimatorEndListener;
}
+ /**
+ * Interface to listen any callbacks when expand animation starts
+ */
+ public interface OnExpandAnimatorStartListener {
+ public void onExpandStart(Card card);
+ }
+
+ /**
+ * Called at the start of Expand Animator
+ */
+ public void onExpandStart() {
+ if (mOnExpandAnimatorStartListener != null) {
+ mOnExpandAnimatorStartListener.onExpandStart(this);
+ }
+ }
+
+ /**
+ * Returns the listener invoked when expand animation starts
+ *
+ * @return listener
+ */
+ public OnExpandAnimatorStartListener getOnExpandAnimatorStartListener() {
+ return mOnExpandAnimatorStartListener;
+ }
+
+ /**
+ * Sets the listener invoked when expand animation ends
+ *
+ * @param onExpandAnimatorStartListener listener
+ */
+ public void setOnExpandAnimatorStartListener(OnExpandAnimatorStartListener onExpandAnimatorStartListener) {
+ this.mOnExpandAnimatorStartListener = onExpandAnimatorStartListener;
+ }
+
// -------------------------------------------------------------
// OnAnimationExpandEnd Interface and Listener
// -------------------------------------------------------------
@@ -605,6 +697,53 @@ public class Card extends BaseCard {
this.mOnCollapseAnimatorEndListener = onCollapseAnimatorEndListener;
}
+ /**
+ * Interface to listen any callbacks when collapse animation starts
+ */
+ public interface OnCollapseAnimatorStartListener {
+ public void onCollapseStart(Card card);
+ }
+
+ /**
+ * Call at the beginning of collapse animation
+ */
+ public void onCollapseStart() {
+ if (mOnCollapseAnimatorStartListener != null) {
+ mOnCollapseAnimatorStartListener.onCollapseStart(this);
+ }
+ }
+
+ /**
+ * Returns the listener invoked when collapse animation starts
+ *
+ * @return listener
+ */
+ public OnCollapseAnimatorStartListener getOnCollapseAnimatorStartListener() {
+ return mOnCollapseAnimatorStartListener;
+ }
+
+ /**
+ * Sets the listener when collapse animation starts
+ *
+ * @param onCollapseAnimatorStartListener
+ */
+ public void setOnCollapseAnimatorStartListener(OnCollapseAnimatorStartListener onCollapseAnimatorStartListener) {
+ this.mOnCollapseAnimatorStartListener = onCollapseAnimatorStartListener;
+ }
+
+
+ public void doExpand(){
+ getCardView().doExpand();
+ }
+
+ public void doCollapse(){
+ getCardView().doCollapse();
+ }
+
+ public void doToogleExpand(){
+ getCardView().doToggleExpand();
+ }
+
// -------------------------------------------------------------
/**
@@ -621,6 +760,24 @@ public class Card extends BaseCard {
// -------------------------------------------------------------
/**
+ * Sets the shadow elevation.
+ * This method works only with the CardViewNative.
+ * @param elevation
+ */
+ public void setCardElevation(float elevation) {
+ this.mCardElevation = elevation;
+ }
+
+ /**
+ * Returns the elevation
+ *
+ * @return
+ */
+ public Float getCardElevation() {
+ return mCardElevation;
+ }
+
+ /**
* Indicates if card has a shadow
*
* @return <code>true</code> if card has a shadow
@@ -692,19 +849,15 @@ public class Card extends BaseCard {
/**
* Indicates if the card is long clickable
- * If card hasn't a {@link OnLongCardClickListener}
- * or any partial Listener return <code>true</code> in any cases.
+ * If card hasn't a {@link OnLongCardClickListener} return <code>false</code> in any cases.
*
* @return
*/
public boolean isLongClickable() {
- if (mIsLongClickable) {
- if (mOnLongClickListener == null
- && (mMultipleOnLongClickListener == null
- || mMultipleOnLongClickListener.isEmpty())) {
+ if (mOnLongClickListener == null) {
+ if (mIsLongClickable)
Log.w(TAG, "LongClickable set to true without onLongClickListener");
- return false;
- }
+ return false;
}
return mIsLongClickable;
}
@@ -777,68 +930,6 @@ public class Card extends BaseCard {
}
/**
- * Adds a LongClickListener on a specific area
- * </p>
- * You can use one of these values:
- * {@link Card#CLICK_LISTENER_ALL_VIEW}
- * {@link Card#CLICK_LISTENER_HEADER_VIEW}
- * {@link Card#CLICK_LISTENER_THUMBNAIL_VIEW}
- * {@link Card#CLICK_LISTENER_CONTENT_VIEW}
- *
- * @param area
- * @param onLongClickListener
- */
- public void addPartialOnLongClickListener(
- int area, OnLongCardClickListener onLongClickListener) {
-
- if (area < CLICK_LISTENER_ALL_VIEW && area > CLICK_LISTENER_CONTENT_VIEW) {
- Log.w(TAG, "area value not valid in addPartialOnLongClickListner");
- }
-
- HashMap multipleOnLongClickListener = getMultipleOnLongClickListener();
- if (onLongClickListener != null) {
- multipleOnLongClickListener.put(area, onLongClickListener);
- mIsLongClickable = true;
- } else {
- removePartialOnLongClickListener(area);
- }
- }
-
- /**
- * Remove LongClickListener from a specif area
- * </p>
- * You can use one of these values:
- * {@link Card#CLICK_LISTENER_ALL_VIEW}
- * {@link Card#CLICK_LISTENER_HEADER_VIEW}
- * {@link Card#CLICK_LISTENER_THUMBNAIL_VIEW}
- * {@link Card#CLICK_LISTENER_CONTENT_VIEW}
- *
- *
- * @param area
- */
- public void removePartialOnLongClickListener(int area) {
-
- HashMap multipleOnLongClickListener = getMultipleOnLongClickListener();
- multipleOnLongClickListener.remove(area);
-
- if (mOnLongClickListener == null && multipleOnLongClickListener.isEmpty()) {
- mIsLongClickable = false;
- }
- }
-
- /**
- * Map for all partial listeners
- *
- * @return a map with partial listeners
- */
- public HashMap<Integer, OnLongCardClickListener> getMultipleOnLongClickListener() {
- if (mMultipleOnLongClickListener != null) {
- return mMultipleOnLongClickListener;
- }
- return mMultipleOnLongClickListener = new HashMap<Integer, OnLongCardClickListener>();
- }
-
- /**
* Indicates if the card is expanded or collapsed
*
* @return <code>true</code> if card is ExpandLayout is visible, otherwise returns <code>false</code>
@@ -911,6 +1002,13 @@ public class Card extends BaseCard {
}
/**
+ * Refreshes the card content (it doesn't inflate layouts again)
+ */
+ public void notifyDataSetChanged(){
+ getCardView().refreshCard(this);
+ }
+
+ /**
* Sets the background drawable resource to override the style of MainLayout (card.main_layout)
*
* @param drawableResourceId drawable resource Id
@@ -1011,4 +1109,30 @@ public class Card extends BaseCard {
public void setViewToClickToExpand(ViewToClickToExpand viewToClickToExpand) {
this.viewToClickToExpand = viewToClickToExpand;
}
+
+ /**
+ * Returns true if the card is using the native card
+ * @return
+ */
+ protected boolean isNative(){
+ if (mCardView!=null)
+ return mCardView.isNative();
+ return false;
+ }
+
+ /**
+ * Set the background color assigned to the Native CardView
+ * @param backgroundColorResourceId
+ */
+ public void setBackgroundColorResourceId(int backgroundColorResourceId) {
+ mBackgroundColorResourceId = backgroundColorResourceId;
+ }
+
+ /**
+ * Returns the background color assigned to the Native CardView
+ * @return
+ */
+ public int getBackgroundColorResourceId() {
+ return mBackgroundColorResourceId;
+ }
}
diff --git a/src/com/android/cards/internal/CardArrayAdapter.java b/src/it/gmariotti/cardslib/library/internal/CardArrayAdapter.java
index 7ec50a7..6c59787 100644
--- a/src/com/android/cards/internal/CardArrayAdapter.java
+++ b/src/it/gmariotti/cardslib/library/internal/CardArrayAdapter.java
@@ -29,17 +29,22 @@ import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.ListView;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import com.android.cards.R;
import com.android.cards.internal.base.BaseCardArrayAdapter;
import com.android.cards.view.CardListView;
+import com.android.cards.view.base.CardViewWrapper;
import com.android.cards.view.CardView;
import com.android.cards.view.listener.SwipeDismissListViewTouchListener;
import com.android.cards.view.listener.SwipeOnScrollListener;
import com.android.cards.view.listener.UndoBarController;
import com.android.cards.view.listener.UndoCard;
+import com.android.cards.view.listener.dismiss.DefaultDismissableManager;
+import com.android.cards.view.listener.dismiss.Dismissable;
/**
* Array Adapter for {@link Card} model
@@ -103,6 +108,10 @@ public class CardArrayAdapter extends BaseCardArrayAdapter implements UndoBarCon
*/
protected HashMap<String /* id */,Card> mInternalObjects;
+ /**
+ * Dismissable Manager
+ */
+ protected Dismissable mDismissable;
// -------------------------------------------------------------
// Constructors
@@ -126,128 +135,107 @@ public class CardArrayAdapter extends BaseCardArrayAdapter implements UndoBarCon
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
- ViewHolder holder;
+ CardViewWrapper mCardView;
+ Card mCard;
+
+ LayoutInflater mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ //Retrieve card from items
+ mCard = (Card) getItem(position);
+ if (mCard != null) {
- // Retrieve card from items
- Card card = (Card) getItem(position);
- if (card != null) {
int layout = mRowLayoutId;
boolean recycle = false;
- // Inflate layout
+ //Inflate layout
if (view == null) {
recycle = false;
- LayoutInflater inflater =
- (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- view = inflater.inflate(layout, parent, false);
-
- holder = new ViewHolder();
- holder.cardView = (CardView) view.findViewById(R.id.list_cardId);
- view.setTag(holder);
+ view = mInflater.inflate(layout, parent, false);
} else {
recycle = true;
- holder = (ViewHolder) view.getTag();
}
- // Setup card
- CardView cardView = holder.cardView;
- if (cardView != null) {
- // It is important to set recycle value for inner layout elements
- cardView.setForceReplaceInnerLayout(
- Card.equalsInnerLayout(cardView.getCard(), card));
+ //Setup card
+ mCardView = (CardViewWrapper) view.findViewById(R.id.list_cardId);
+ if (mCardView != null) {
+ //It is important to set recycle value for inner layout elements
+ mCardView.setForceReplaceInnerLayout(Card.equalsInnerLayout(mCardView.getCard(),mCard));
- // It is important to set recycle value for performance issue
- cardView.setRecycle(recycle);
+ //It is important to set recycle value for performance issue
+ mCardView.setRecycle(recycle);
- // Save original swipeable to prevent cardSwipeListener
- // (listView requires another cardSwipeListener)
- boolean origianlSwipeable = card.isSwipeable();
- card.setSwipeable(false);
+ //Save original swipeable to prevent cardSwipeListener (listView requires another cardSwipeListener)
+ boolean origianlSwipeable = mCard.isSwipeable();
+ mCard.setSwipeable(false);
- cardView.setCard(card);
+ mCardView.setCard(mCard);
- // Set originalValue
- card.setSwipeable(origianlSwipeable);
+ //Set originalValue
+ mCard.setSwipeable(origianlSwipeable);
- // If card has an expandable button override animation
- if ((card.getCardHeader() != null
- && card.getCardHeader().isButtonExpandVisible())
- || card.getViewToClickToExpand() != null) {
- setupExpandCollapseListAnimation(cardView);
+ //If card has an expandable button override animation
+ if ((mCard.getCardHeader() != null && mCard.getCardHeader().isButtonExpandVisible()) || mCard.getViewToClickToExpand()!=null ){
+ setupExpandCollapseListAnimation(mCardView);
}
- // Setup swipeable animation
- setupSwipeableAnimation(card, cardView);
+ //Setup swipeable animation
+ setupSwipeableAnimation(mCard, mCardView);
//setupMultiChoice
- setupMultichoice(view, card, cardView, position);
+ setupMultichoice(view,mCard,mCardView,position);
}
}
return view;
}
- static class ViewHolder {
- CardView cardView;
- }
/**
* Sets SwipeAnimation on List
*
* @param card {@link Card}
- * @param cardView {@link CardView}
+ * @param cardView {@link com.android.cards.view.base.CardViewWrapper}
*/
- protected void setupSwipeableAnimation(final Card card, CardView cardView) {
- HashMap<Integer, Card.OnLongCardClickListener> multipleOnLongClickListner =
- card.getMultipleOnLongClickListener();
- if (card.isSwipeable()) {
- if (mOnTouchListener == null) {
+ protected void setupSwipeableAnimation(final Card card, CardViewWrapper cardView) {
+
+ if (card.isSwipeable()){
+ if (mOnTouchListener == null){
mOnTouchListener = new SwipeDismissListViewTouchListener(mCardListView, mCallback);
+
+ //Configure the default DismissableManager
+ if (mDismissable == null) mDismissable = new DefaultDismissableManager();
+ mDismissable.setAdapter(this);
+ mOnTouchListener.setDismissable(mDismissable);
+
// Setting this scroll listener is required to ensure that during
// ListView scrolling, we don't look for swipes.
- if (mCardListView.getOnScrollListener() == null) {
+ if (mCardListView.getOnScrollListener() == null){
SwipeOnScrollListener scrollListener = new SwipeOnScrollListener();
scrollListener.setTouchListener(mOnTouchListener);
mCardListView.setOnScrollListener(scrollListener);
- } else {
+ }else{
AbsListView.OnScrollListener onScrollListener=mCardListView.getOnScrollListener();
- if (onScrollListener instanceof SwipeOnScrollListener) {
+ if (onScrollListener instanceof SwipeOnScrollListener)
((SwipeOnScrollListener) onScrollListener).setTouchListener(mOnTouchListener);
- }
}
+
mCardListView.setOnTouchListener(mOnTouchListener);
}
cardView.setOnTouchListener(mOnTouchListener);
- // We may have partial onlongclicklistener. Restore onTouchListener for this views.
- setPartialOnTouchListeners(cardView, mOnTouchListener, multipleOnLongClickListner);
- } else {
+ }else{
//prevent issue with recycle view
cardView.setOnTouchListener(null);
- setPartialOnTouchListeners(cardView, null, multipleOnLongClickListner);
- }
- }
-
- private void setPartialOnTouchListeners(CardView cardView,
- SwipeDismissListViewTouchListener onTouchListener,
- HashMap<Integer, Card.OnLongCardClickListener> multipleOnLongClickListner) {
- if (multipleOnLongClickListner != null && !multipleOnLongClickListner.isEmpty()) {
- for (int key : multipleOnLongClickListner.keySet()) {
- View viewLongClickable = cardView.decodeAreaOnClickListener(key);
- if (viewLongClickable != null) {
- viewLongClickable.setOnTouchListener(mOnTouchListener);
- }
- }
}
}
/**
* Overrides the default collapse/expand animation in a List
*
- * @param cardView {@link CardView}
+ * @param cardView {@link com.android.cards.view.base.CardViewWrapper}
*/
- protected void setupExpandCollapseListAnimation(CardView cardView) {
+ protected void setupExpandCollapseListAnimation(CardViewWrapper cardView) {
if (cardView == null) return;
cardView.setOnExpandListAnimatorListener(mCardListView);
@@ -263,7 +251,7 @@ public class CardArrayAdapter extends BaseCardArrayAdapter implements UndoBarCon
@Override
public boolean canDismiss(int position, Card card) {
- return card.isSwipeable();
+ return mDismissable.isDismissable(position, card);
}
@Override
@@ -273,16 +261,36 @@ public class CardArrayAdapter extends BaseCardArrayAdapter implements UndoBarCon
String[] itemIds=new String[reverseSortedPositions.length];
int i=0;
+ // Keep track of the cards that will be removed
+ final ArrayList<Card> removedCards = new ArrayList<Card>();
+
//Remove cards and notifyDataSetChanged
for (int position : reverseSortedPositions) {
- Card card = getItem(position);
- itemPositions[i]=position;
- itemIds[i]=card.getId();
- i++;
- remove(card);
- if (card.getOnSwipeListener() != null){
+ Card card = null;
+ if (listView.getAdapter() != null && listView.getAdapter().getItem(position) instanceof Card)
+ card = (Card) listView.getAdapter().getItem(position);
+ //Card card = getItem(position);
+
+ if (card != null) {
+ itemPositions[i] = position;
+ itemIds[i] = card.getId();
+ i++;
+
+ /*
+ if (card.isExpanded()){
+ if (card.getCardView()!=null && card.getCardView().getOnExpandListAnimatorListener()!=null){
+ //There is a List Animator.
+ card.getCardView().getOnExpandListAnimatorListener().onCollapseStart(card.getCardView(), card.getCardView().getInternalExpandLayout());
+ }
+ }*/
+ removedCards.add(card);
+ remove(card);
+ if (card.getOnSwipeListener() != null) {
card.getOnSwipeListener().onSwipe(card);
+ }
+ }else{
+ Log.e(TAG,"Error on swipe action. Impossible to retrieve the card from position");
}
}
notifyDataSetChanged();
@@ -293,18 +301,41 @@ public class CardArrayAdapter extends BaseCardArrayAdapter implements UndoBarCon
//Show UndoBar
UndoCard itemUndo=new UndoCard(itemPositions,itemIds);
- if (getContext()!=null){
- Resources res = getContext().getResources();
- if (res!=null){
- String messageUndoBar = res.getQuantityString(R.plurals.list_card_undo_items, reverseSortedPositions.length, reverseSortedPositions.length);
+ //MessageUndoBar
+ String messageUndoBar=null;
+ if (getUndoBarController().getUndoBarUIElements()!=null){
+ messageUndoBar = getUndoBarController().getUndoBarUIElements().getMessageUndo(CardArrayAdapter.this,itemIds,itemPositions);
+ }
- mUndoBarController.showUndoBar(
- false,
- messageUndoBar,
- itemUndo);
+ //Default message if null
+ if (messageUndoBar == null) {
+ if (getContext() != null) {
+ Resources res = getContext().getResources();
+ if (res != null) {
+ messageUndoBar = res.getQuantityString(R.plurals.list_card_undo_items, reverseSortedPositions.length, reverseSortedPositions.length);
+ }
}
}
+ mUndoBarController.showUndoBar(
+ false,
+ messageUndoBar,
+ itemUndo,
+ new UndoBarController.UndoBarHideListener() {
+ @Override
+ public void onUndoBarHide(boolean undoOccurred) {
+ // Remove the items from mInternalObjects, if
+ // the undo was not triggered, since they are
+ // now permanently removed from the underlying Array.
+ if (!undoOccurred) {
+ for (Card card : removedCards) {
+ if (card.getOnUndoHideSwipeListListener()!=null)
+ card.getOnUndoHideSwipeListListener().onUndoHideSwipe(card);
+ mInternalObjects.remove(card.getId());
+ }
+ }
+ }
+ });
}
}
};
@@ -374,9 +405,14 @@ public class CardArrayAdapter extends BaseCardArrayAdapter implements UndoBarCon
if (mUndoBarUIElements==null)
mUndoBarUIElements=new UndoBarController.DefaultUndoBarUIElements();
- View undobar = ((Activity)mContext).findViewById(mUndoBarUIElements.getUndoBarId());
- if (undobar != null) {
- mUndoBarController = new UndoBarController(undobar, this,mUndoBarUIElements);
+ if (mContext!=null && mContext instanceof Activity) {
+ View undobar = ((Activity) mContext).findViewById(mUndoBarUIElements.getUndoBarId());
+ if (undobar != null) {
+ mUndoBarController = new UndoBarController(undobar, this, mUndoBarUIElements);
+ }
+ }else{
+ Log.e(TAG,"Undo Action requires a valid Activity context");
+ throw new IllegalArgumentException("Undo Action requires a valid Activity context");
}
}
}else{
@@ -384,6 +420,57 @@ public class CardArrayAdapter extends BaseCardArrayAdapter implements UndoBarCon
}
}
+ // ---------------------------------------------------------------------
+ // Override Array Manipulation Methods To Keep mInternalObjects in Sync
+ // ---------------------------------------------------------------------
+
+ // public void remove() intentionally omitted, since mInternalObjects needs
+ // to keep a reference so the remove can be undone, if necessary.
+
+ @Override
+ public void add(Card card) {
+ super.add(card);
+ if (mEnableUndo) {
+ mInternalObjects.put(card.getId(), card);
+ }
+ }
+
+ @Override
+ public void addAll(Collection<? extends Card> cardCollection) {
+ super.addAll(cardCollection);
+ if (mEnableUndo) {
+ for (Card card : cardCollection) {
+ mInternalObjects.put(card.getId(), card);
+ }
+ }
+ }
+
+ @Override
+ public void addAll(Card...cards) {
+ super.addAll(cards);
+ if (mEnableUndo) {
+ for (Card card : cards) {
+ mInternalObjects.put(card.getId(), card);
+ }
+ }
+ }
+
+ @Override
+ public void clear() {
+ super.clear();
+ if (mEnableUndo) {
+ mInternalObjects.clear();
+ }
+ }
+
+ @Override
+ public void insert(Card card, int index) {
+ super.insert(card, index);
+ if (mEnableUndo) {
+ mInternalObjects.put(card.getId(), card);
+ }
+ }
+
// -------------------------------------------------------------
// Getters and Setters
// -------------------------------------------------------------
@@ -414,4 +501,13 @@ public class CardArrayAdapter extends BaseCardArrayAdapter implements UndoBarCon
public UndoBarController getUndoBarController() {
return mUndoBarController;
}
+
+ /**
+ * Sets a custom DismissableManager
+ * @param dismissable
+ */
+ public void setDismissable(Dismissable dismissable) {
+ mDismissable = dismissable;
+ }
+
}
diff --git a/src/com/android/cards/internal/CardArrayMultiChoiceAdapter.java b/src/it/gmariotti/cardslib/library/internal/CardArrayMultiChoiceAdapter.java
index 2ba4735..2d15bbb 100644
--- a/src/com/android/cards/internal/CardArrayMultiChoiceAdapter.java
+++ b/src/it/gmariotti/cardslib/library/internal/CardArrayMultiChoiceAdapter.java
@@ -33,7 +33,8 @@ import com.android.cards.internal.multichoice.MultiChoiceAdapter;
import com.android.cards.internal.multichoice.MultiChoiceAdapterHelperBase;
import com.android.cards.internal.multichoice.OptionMultiChoice;
import com.android.cards.view.CardListView;
-import com.android.cards.view.CardView;
+import com.android.cards.view.base.CardViewWrapper;
+
/**
* @author Gabriele Mariotti (gabri.mariotti@gmail.com)
@@ -96,7 +97,7 @@ public abstract class CardArrayMultiChoiceAdapter extends CardArrayAdapter imple
* @param position
*/
@Override
- protected void setupMultichoice(View view, Card mCard, CardView mCardView, long position) {
+ protected void setupMultichoice(View view, Card mCard, CardViewWrapper mCardView, long position) {
super.setupMultichoice(view, mCard, mCardView, position);
mHelper.setupMultichoice(view, mCard, mCardView, position);
}
diff --git a/src/com/android/cards/internal/CardCursorAdapter.java b/src/it/gmariotti/cardslib/library/internal/CardCursorAdapter.java
index 65f77bd..7520c04 100644
--- a/src/com/android/cards/internal/CardCursorAdapter.java
+++ b/src/it/gmariotti/cardslib/library/internal/CardCursorAdapter.java
@@ -32,7 +32,8 @@ import java.util.List;
import com.android.cards.R;
import com.android.cards.internal.base.BaseCardCursorAdapter;
import com.android.cards.view.CardListView;
-import com.android.cards.view.CardView;
+import com.android.cards.view.base.CardViewWrapper;
+
/**
* Cursor Adapter for {@link com.android.cards.internal.Card} model
@@ -57,31 +58,31 @@ public abstract class CardCursorAdapter extends BaseCardCursorAdapter {
protected HashMap<String /* id */,Card> mInternalObjects;
+ /**
+ * All ids expanded
+ */
protected final List<String> mExpandedIds;
/**
* Recycle
*/
- private boolean recycle = false;
+ protected boolean recycle = false;
// -------------------------------------------------------------
// Constructors
// -------------------------------------------------------------
public CardCursorAdapter(Context context) {
- super(context, null, false);
- mContext= context;
+ super(context, null, 0);
mExpandedIds = new ArrayList<String>();
}
protected CardCursorAdapter(Context context, Cursor c, boolean autoRequery) {
super(context, c, autoRequery);
- mContext= context;
mExpandedIds = new ArrayList<String>();
}
protected CardCursorAdapter(Context context, Cursor c, int flags) {
super(context, c, flags);
- mContext= context;
mExpandedIds = new ArrayList<String>();
}
@@ -111,12 +112,12 @@ public abstract class CardCursorAdapter extends BaseCardCursorAdapter {
@Override
public void bindView(View view, Context context, Cursor cursor) {
- CardView mCardView;
+ CardViewWrapper mCardView;
Card mCard;
mCard = (Card) getCardFromCursor(cursor);
if (mCard != null) {
- mCardView = (CardView) view.findViewById(R.id.list_cardId);
+ mCardView = (CardViewWrapper) view.findViewById(R.id.list_cardId);
if (mCardView != null) {
//It is important to set recycle value for inner layout elements
mCardView.setForceReplaceInnerLayout(Card.equalsInnerLayout(mCardView.getCard(),mCard));
@@ -145,6 +146,8 @@ public abstract class CardCursorAdapter extends BaseCardCursorAdapter {
//Setup swipeable animation
setupSwipeableAnimation(mCard, mCardView);
+ //setupMultiChoice
+ setupMultichoice(view,mCard,mCardView,cursor.getPosition());
}
}
}
@@ -156,7 +159,7 @@ public abstract class CardCursorAdapter extends BaseCardCursorAdapter {
* @param card {@link com.android.cards.internal.Card}
* @param cardView {@link com.android.cards.view.CardView}
*/
- protected void setupSwipeableAnimation(final Card card, CardView cardView) {
+ protected void setupSwipeableAnimation(final Card card, CardViewWrapper cardView) {
cardView.setOnTouchListener(null);
}
@@ -166,7 +169,7 @@ public abstract class CardCursorAdapter extends BaseCardCursorAdapter {
*
* @param cardView {@link com.android.cards.view.CardView}
*/
- protected void setupExpandCollapseListAnimation(CardView cardView) {
+ protected void setupExpandCollapseListAnimation(CardViewWrapper cardView) {
if (cardView == null) return;
cardView.setOnExpandListAnimatorListener(mCardListView);
@@ -236,7 +239,7 @@ public abstract class CardCursorAdapter extends BaseCardCursorAdapter {
* @param viewCard
* @return
*/
- public boolean onExpandStart(CardView viewCard) {
+ public boolean onExpandStart(CardViewWrapper viewCard) {
Card card = viewCard.getCard();
if (card!=null){
String itemId = card.getId();
@@ -253,7 +256,7 @@ public abstract class CardCursorAdapter extends BaseCardCursorAdapter {
* @param viewCard
* @return
*/
- public boolean onCollapseStart(CardView viewCard) {
+ public boolean onCollapseStart(CardViewWrapper viewCard) {
Card card = viewCard.getCard();
if (card!=null){
String itemId = card.getId();
@@ -269,7 +272,7 @@ public abstract class CardCursorAdapter extends BaseCardCursorAdapter {
*
* @param viewCard
*/
- public void onExpandEnd(CardView viewCard) {
+ public void onExpandEnd(CardViewWrapper viewCard) {
Card card = viewCard.getCard();
if (card!=null){
setExpanded(card);
@@ -281,7 +284,7 @@ public abstract class CardCursorAdapter extends BaseCardCursorAdapter {
*
* @param viewCard
*/
- public void onCollapseEnd(CardView viewCard) {
+ public void onCollapseEnd(CardViewWrapper viewCard) {
Card card = viewCard.getCard();
if (card!=null){
setCollapsed(card);
diff --git a/src/it/gmariotti/cardslib/library/internal/CardCursorMultiChoiceAdapter.java b/src/it/gmariotti/cardslib/library/internal/CardCursorMultiChoiceAdapter.java
new file mode 100644
index 0000000..87a6498
--- /dev/null
+++ b/src/it/gmariotti/cardslib/library/internal/CardCursorMultiChoiceAdapter.java
@@ -0,0 +1,162 @@
+package com.android.cards.internal;
+
+import android.app.Activity;
+import android.content.Context;
+import android.view.ActionMode;
+import android.view.Menu;
+import android.view.View;
+import android.widget.AbsListView;
+
+import java.util.ArrayList;
+
+import com.android.cards.internal.multichoice.DefaultOptionMultiChoice;
+import com.android.cards.internal.multichoice.MultiChoiceAdapter;
+import com.android.cards.internal.multichoice.MultiChoiceAdapterHelperBase;
+import com.android.cards.internal.multichoice.OptionMultiChoice;
+import com.android.cards.view.CardListView;
+import com.android.cards.view.base.CardViewWrapper;
+
+
+public abstract class CardCursorMultiChoiceAdapter extends CardCursorAdapter implements MultiChoiceAdapter, AbsListView.MultiChoiceModeListener {
+
+ /**
+ * Helper
+ */
+ private MultiChoiceAdapterHelperBase mHelper = new MultiChoiceAdapterHelperBase(this);
+
+
+ /**
+ * Option for multichoice
+ */
+ protected OptionMultiChoice mOptions;
+
+ // -------------------------------------------------------------
+ // Constructors
+ // -------------------------------------------------------------
+
+ /**
+ * Constructor
+ *
+ * @param context The current context.
+ */
+ public CardCursorMultiChoiceAdapter(Context context) {
+ this(context, new DefaultOptionMultiChoice());
+ }
+
+ /**
+ * Constructor
+ *
+ * @param context The current context.
+ */
+ public CardCursorMultiChoiceAdapter(Context context, OptionMultiChoice options) {
+ super(context, null, true);
+ this.mOptions = options;
+ mHelper.setMultiChoiceModeListener(this);
+ }
+
+ // -------------------------------------------------------------
+ // Adapter
+ // -------------------------------------------------------------
+
+ @Override
+ public void setCardListView(CardListView cardListView) {
+ super.setCardListView(cardListView);
+ mHelper.setAdapterView(cardListView);
+ }
+
+ /**
+ * Used to setup some element events for multichoice
+ *
+ * @param view
+ * @param mCard
+ * @param mCardView
+ * @param position
+ */
+ @Override
+ protected void setupMultichoice(View view, Card mCard, CardViewWrapper mCardView, long position) {
+ super.setupMultichoice(view, mCard, mCardView, position);
+ mHelper.setupMultichoice(view, mCard, mCardView, position);
+ }
+
+
+ @Override
+ public Card getItem(int position) {
+ Card card = super.getItem(position);
+ card.mMultiChoiceEnabled = true;
+ return card;
+ }
+
+ // -------------------------------------------------------------
+ // ActionMode
+ // -------------------------------------------------------------
+
+ public boolean startActionMode(Activity activity) {
+ return mHelper.startActionMode(activity);
+ }
+
+ /**
+ * Called when action mode is first created. The menu supplied will be used to
+ * generate action buttons for the action mode.
+ *
+ * @param mode ActionMode being created
+ * @param menu Menu used to populate action buttons
+ * @return true if the action mode should be created, false if entering this
+ * mode should be aborted.
+ */
+ @Override
+ public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+ return mHelper.onCreateActionMode(mode,menu);
+ }
+
+
+ /**
+ * Called when an action mode is about to be exited and destroyed.
+ *
+ * @param mode The current ActionMode being destroyed
+ */
+ @Override
+ public void onDestroyActionMode(ActionMode mode) {
+ mHelper.onDestroyActionMode(mode);
+ }
+
+ /**
+ * Called when an item is checked or unchecked during selection mode.
+ *
+ * @param mode The {@link ActionMode} providing the selection mode
+ * @param position Adapter position of the item that was checked or unchecked
+ * @param id Adapter ID of the item that was checked or unchecked
+ * @param checked <code>true</code> if the item is now checked, <code>false</code>
+ * if the item is now unchecked.
+ */
+ @Override
+ public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
+ mHelper.onItemCheckedStateChanged(mode,position,id,checked);
+ }
+
+ /**
+ * Indicate if action mode is started
+ *
+ * @return
+ */
+ @Override
+ public boolean isActionModeStarted() {
+ return mHelper.isActionModeStarted();
+ }
+
+ // -------------------------------------------------------------
+ // MultiChoice
+ // -------------------------------------------------------------
+
+ /**
+ * Returns the selected cards
+ * @return
+ */
+ protected ArrayList<Card> getSelectedCards() {
+ return mHelper.getSelectedCards();
+ }
+
+ @Override
+ public OptionMultiChoice getOptionMultiChoice() {
+ return mOptions;
+ }
+}
diff --git a/src/com/android/cards/internal/CardExpand.java b/src/it/gmariotti/cardslib/library/internal/CardExpand.java
index e0d34fe..c1e313e 100644
--- a/src/com/android/cards/internal/CardExpand.java
+++ b/src/it/gmariotti/cardslib/library/internal/CardExpand.java
@@ -83,6 +83,7 @@ import com.android.cards.internal.base.BaseCard;
*/
public class CardExpand extends BaseCard {
+ private boolean couldUseNativeInnerLayout = false;
// -------------------------------------------------------------
// Constructors
@@ -106,6 +107,9 @@ public class CardExpand extends BaseCard {
public CardExpand(Context context, int innerLayout) {
super(context);
mInnerLayout= innerLayout;
+
+ if (innerLayout == R.layout.inner_base_expand)
+ couldUseNativeInnerLayout = true;
}
// -------------------------------------------------------------
@@ -124,6 +128,10 @@ public class CardExpand extends BaseCard {
@Override
public View getInnerView(Context context, ViewGroup parent) {
+ //Check if the default inner layout could be the native layout
+ if (couldUseNativeInnerLayout && isNative())
+ mInnerLayout = R.layout.native_inner_base_expand;
+
//Inflate the inner layout
View view= super.getInnerView(context, parent);
@@ -145,7 +153,6 @@ public class CardExpand extends BaseCard {
* This method sets values to expand elements and customizes view.
*
* Override this method to customize your Expand View
- * If you use listviews it is recommend to user a Viewholder like here.
*
* @param parent Expand external Layout
* @param view inner-expand view
@@ -153,25 +160,23 @@ public class CardExpand extends BaseCard {
@Override
public void setupInnerViewElements(ViewGroup parent, View view) {
- // Add simple title to expand area
- if (view != null) {
- ViewHolder holder;
- holder = (ViewHolder) view.getTag();
-
- if (holder == null) {
- holder = new ViewHolder();
- holder.titleView =
- (TextView) view.findViewById(R.id.card_expand_inner_simple_title);
- view.setTag(holder);
- }
- if (holder.titleView != null) {
- holder.titleView.setText(mTitle);
- }
+ //Add simple title to expand area
+ if (view!=null){
+ TextView mTitleView=(TextView) view.findViewById(R.id.card_expand_inner_simple_title);
+ if (mTitleView!=null)
+ mTitleView.setText(mTitle);
}
}
- static class ViewHolder {
- TextView titleView;
+ /**
+ * Returns true if the card is using the native card
+ * @return
+ */
+ protected boolean isNative(){
+ if (getParentCard() != null)
+ return getParentCard().isNative();
+ return false;
}
+
}
diff --git a/src/it/gmariotti/cardslib/library/internal/CardExpandableListAdapter.java b/src/it/gmariotti/cardslib/library/internal/CardExpandableListAdapter.java
new file mode 100644
index 0000000..5d82d7a
--- /dev/null
+++ b/src/it/gmariotti/cardslib/library/internal/CardExpandableListAdapter.java
@@ -0,0 +1,220 @@
+/*
+ * ******************************************************************************
+ * Copyright (c) 2013-2014 Gabriele Mariotti.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * *****************************************************************************
+ */
+
+package com.android.cards.internal;
+
+import android.content.Context;
+import android.util.SparseArray;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseExpandableListAdapter;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.cards.R;
+import com.android.cards.view.CardExpandableListView;
+import com.android.cards.view.base.CardViewWrapper;
+
+
+/**
+ * @author Gabriele Mariotti (gabri.mariotti@gmail.com)
+ */
+public class CardExpandableListAdapter<T> extends BaseExpandableListAdapter {
+
+ protected final SparseArray<BaseGroupExpandableCard<T>> cards;
+ public LayoutInflater mInflater;
+
+ /**
+ * Current context
+ */
+ protected Context mContext;
+
+ /**
+ * Default layout used for each row
+ */
+ protected int mGroupLayoutId = R.layout.list_card_layout;
+
+ /**
+ * Default layout used for each row
+ */
+ protected int mChildLayoutId = R.layout.base_list_expandable_children_layout;
+
+ /**
+ * {@link CardExpandableListView}
+ */
+ protected CardExpandableListView mCardListView;
+
+ // -------------------------------------------------------------
+ // Constructors
+ // -------------------------------------------------------------
+
+ public CardExpandableListAdapter(Context context, SparseArray<BaseGroupExpandableCard<T>> cards) {
+ this.cards = cards;
+ mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ }
+
+ @Override
+ public int getGroupCount() {
+ return cards.size();
+ }
+
+ @Override
+ public int getChildrenCount(int groupPosition) {
+ return cards.get(groupPosition).children.size();
+ }
+
+
+ @Override
+ public Card getGroup(int groupPosition) {
+ return cards.get(groupPosition);
+ }
+
+
+ @Override
+ public T getChild(int groupPosition, int childPosition) {
+ return cards.get(groupPosition).children.get(childPosition);
+ }
+
+ @Override
+ public long getGroupId(int groupPosition) {
+ if (getGroup(groupPosition).getId()!=null)
+ return getGroup(groupPosition).getId().hashCode();
+ else
+ return groupPosition;
+ }
+
+ @Override
+ public long getChildId(int groupPosition, int childPosition) {
+ return childPosition;
+ }
+
+ @Override
+ public boolean hasStableIds() {
+ return false;
+ }
+
+ @Override
+ public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
+
+ View view = convertView;
+ CardViewWrapper mCardView;
+
+ Card mCard = (Card) getGroup(groupPosition);
+ if (mCard != null) {
+ int layout = mGroupLayoutId;
+ boolean recycle = false;
+
+ //Inflate layout
+ if (view == null) {
+ recycle = false;
+ view = mInflater.inflate(layout, parent, false);
+ } else {
+ recycle = true;
+ }
+
+ //Setup card
+ mCardView = (CardViewWrapper) view.findViewById(R.id.list_cardId);
+ if (mCardView != null) {
+ //It is important to set recycle value for inner layout elements
+ mCardView.setForceReplaceInnerLayout(Card.equalsInnerLayout(mCardView.getCard(), mCard));
+
+ //It is important to set recycle value for performance issue
+ mCardView.setRecycle(recycle);
+
+ mCard.setSwipeable(false);
+
+ mCardView.setCard(mCard);
+
+ }
+ }
+
+ return view;
+ }
+
+ @Override
+ public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
+
+ T obj = getChild(groupPosition, childPosition);
+
+ if (obj != null && obj instanceof String) {
+ final String children = (String) obj;
+
+ TextView text = null;
+ if (convertView == null) {
+ convertView = mInflater.inflate(mChildLayoutId, null);
+ }
+ text = (TextView) convertView.findViewById(R.id.card_children_simple_title);
+ text.setText(children);
+
+ registerClickListener(convertView, obj, groupPosition, childPosition);
+ }
+ return convertView;
+ }
+
+
+ protected void registerClickListener(View convertView, T obj, int groupPosition, int childPosition) {
+ if (isChildSelectable(groupPosition, childPosition)) {
+ final T children = obj;
+ convertView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Toast.makeText(mContext, children.toString(), Toast.LENGTH_SHORT).show();
+ }
+ });
+ }
+ }
+
+
+ @Override
+ public boolean isChildSelectable(int groupPosition, int childPosition) {
+ return true;
+ }
+
+ // -------------------------------------------------------------
+ // Getters and Setters
+ // -------------------------------------------------------------
+
+ /**
+ * Returns current context
+ *
+ * @return current context
+ */
+ public Context getContext() {
+ return mContext;
+ }
+
+ /**
+ * Sets layout resource ID used by rows
+ *
+ * @param groupLayoutId layout resource id
+ */
+ public void setGroupLayoutId(int groupLayoutId) {
+ this.mGroupLayoutId = groupLayoutId;
+ }
+
+
+ public CardExpandableListView getCardListView() {
+ return mCardListView;
+ }
+
+ public void setCardListView(CardExpandableListView cardListView) {
+ mCardListView = cardListView;
+ }
+
+}
diff --git a/src/com/android/cards/internal/CardGridArrayAdapter.java b/src/it/gmariotti/cardslib/library/internal/CardGridArrayAdapter.java
index 6fefa0a..132198b 100644
--- a/src/com/android/cards/internal/CardGridArrayAdapter.java
+++ b/src/it/gmariotti/cardslib/library/internal/CardGridArrayAdapter.java
@@ -29,7 +29,7 @@ import java.util.List;
import com.android.cards.R;
import com.android.cards.internal.base.BaseCardArrayAdapter;
import com.android.cards.view.CardGridView;
-import com.android.cards.view.CardView;
+import com.android.cards.view.base.CardViewWrapper;
import com.android.cards.view.listener.SwipeDismissListViewTouchListener;
/**
@@ -86,11 +86,6 @@ public class CardGridArrayAdapter extends BaseCardArrayAdapter {
*/
protected SwipeDismissListViewTouchListener mOnTouchListener;
- /**
- * List of cards represented in the ListView.
- */
- private List<Card> cards;
-
// -------------------------------------------------------------
// Constructors
@@ -104,7 +99,6 @@ public class CardGridArrayAdapter extends BaseCardArrayAdapter {
*/
public CardGridArrayAdapter(Context context, List<Card> cards) {
super(context, cards);
- this.cards = cards;
}
// -------------------------------------------------------------
@@ -115,13 +109,13 @@ public class CardGridArrayAdapter extends BaseCardArrayAdapter {
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
- CardView mCardView;
+ CardViewWrapper mCardView;
Card mCard;
LayoutInflater mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//Retrieve card from items
- mCard = getItem(position);
+ mCard = (Card) getItem(position);
if (mCard != null) {
int layout = mRowLayoutId;
@@ -136,7 +130,7 @@ public class CardGridArrayAdapter extends BaseCardArrayAdapter {
}
//Setup card
- mCardView = (CardView) view.findViewById(R.id.list_cardId);
+ mCardView = (CardViewWrapper) view.findViewById(R.id.list_cardId);
if (mCardView != null) {
//It is important to set recycle value for inner layout elements
mCardView.setForceReplaceInnerLayout(Card.equalsInnerLayout(mCardView.getCard(),mCard));
@@ -171,23 +165,13 @@ public class CardGridArrayAdapter extends BaseCardArrayAdapter {
return view;
}
- @Override
- public int getCount() {
- return cards.size();
- }
-
- @Override
- public Card getItem(int pos){
- return cards.get(pos);
- }
-
/**
* Removes SwipeAnimation on Grid
*
* @param card {@link Card}
- * @param cardView {@link CardView}
+ * @param cardView {@link com.android.cards.view.base.CardViewWrapper}
*/
- protected void setupSwipeableAnimation(final Card card, CardView cardView) {
+ protected void setupSwipeableAnimation(final Card card, CardViewWrapper cardView) {
cardView.setOnTouchListener(null);
}
@@ -197,7 +181,7 @@ public class CardGridArrayAdapter extends BaseCardArrayAdapter {
*
* @param cardView {@link com.android.cards.view.CardView}
*/
- protected void setupExpandCollapseListAnimation(CardView cardView) {
+ protected void setupExpandCollapseListAnimation(CardViewWrapper cardView) {
if (cardView == null) return;
cardView.setOnExpandListAnimatorListener(mCardGridView);
diff --git a/src/com/android/cards/internal/CardGridArrayMultiChoiceAdapter.java b/src/it/gmariotti/cardslib/library/internal/CardGridArrayMultiChoiceAdapter.java
index 286feab..5b36174 100644
--- a/src/com/android/cards/internal/CardGridArrayMultiChoiceAdapter.java
+++ b/src/it/gmariotti/cardslib/library/internal/CardGridArrayMultiChoiceAdapter.java
@@ -33,7 +33,8 @@ import com.android.cards.internal.multichoice.MultiChoiceAdapter;
import com.android.cards.internal.multichoice.MultiChoiceAdapterHelperBase;
import com.android.cards.internal.multichoice.OptionMultiChoice;
import com.android.cards.view.CardGridView;
-import com.android.cards.view.CardView;
+import com.android.cards.view.base.CardViewWrapper;
+
/**
* @author Gabriele Mariotti (gabri.mariotti@gmail.com)
@@ -96,7 +97,7 @@ public abstract class CardGridArrayMultiChoiceAdapter extends CardGridArrayAdapt
* @param position
*/
@Override
- protected void setupMultichoice(View view, Card mCard, CardView mCardView, long position) {
+ protected void setupMultichoice(View view, Card mCard, CardViewWrapper mCardView, long position) {
super.setupMultichoice(view, mCard, mCardView, position);
mHelper.setupMultichoice(view,mCard,mCardView,position);
}
diff --git a/src/com/android/cards/internal/CardGridCursorAdapter.java b/src/it/gmariotti/cardslib/library/internal/CardGridCursorAdapter.java
index c87ee3e..d111303 100644
--- a/src/com/android/cards/internal/CardGridCursorAdapter.java
+++ b/src/it/gmariotti/cardslib/library/internal/CardGridCursorAdapter.java
@@ -30,7 +30,8 @@ import java.util.HashMap;
import com.android.cards.R;
import com.android.cards.internal.base.BaseCardCursorAdapter;
import com.android.cards.view.CardGridView;
-import com.android.cards.view.CardView;
+import com.android.cards.view.base.CardViewWrapper;
+
/**
* Cursor Adapter for {@link Card} model
@@ -63,18 +64,15 @@ public abstract class CardGridCursorAdapter extends BaseCardCursorAdapter {
// -------------------------------------------------------------
public CardGridCursorAdapter(Context context) {
- super(context, null, false);
- mContext= context;
+ super(context, null, 0);
}
protected CardGridCursorAdapter(Context context, Cursor c, boolean autoRequery) {
super(context, c, autoRequery);
- mContext= context;
}
protected CardGridCursorAdapter(Context context, Cursor c, int flags) {
super(context, c, flags);
- mContext= context;
}
// -------------------------------------------------------------
@@ -103,12 +101,12 @@ public abstract class CardGridCursorAdapter extends BaseCardCursorAdapter {
@Override
public void bindView(View view, Context context, Cursor cursor) {
- CardView mCardView;
+ CardViewWrapper mCardView;
Card mCard;
mCard = (Card) getCardFromCursor(cursor);
if (mCard != null) {
- mCardView = (CardView) view.findViewById(R.id.list_cardId);
+ mCardView = (CardViewWrapper) view.findViewById(R.id.list_cardId);
if (mCardView != null) {
//It is important to set recycle value for inner layout elements
mCardView.setForceReplaceInnerLayout(Card.equalsInnerLayout(mCardView.getCard(),mCard));
@@ -148,18 +146,9 @@ public abstract class CardGridCursorAdapter extends BaseCardCursorAdapter {
* @param card {@link Card}
* @param cardView {@link com.android.cards.view.CardView}
*/
- protected void setupSwipeableAnimation(final Card card, CardView cardView) {
- cardView.setOnTouchListener(null);
- }
+ protected void setupSwipeableAnimation(final Card card, CardViewWrapper cardView) {
- /**
- * Overrides the default collapse/expand animation in a List
- *
- * @param cardView {@link com.android.cards.view.CardView}
- */
- protected void setupExpandCollapseListAnimation(CardView cardView) {
- if (cardView == null) return;
- cardView.setOnExpandListAnimatorListener(mCardGridView);
+ cardView.setOnTouchListener(null);
}
diff --git a/src/com/android/cards/internal/CardHeader.java b/src/it/gmariotti/cardslib/library/internal/CardHeader.java
index 49b8bed..6fd3461 100644
--- a/src/com/android/cards/internal/CardHeader.java
+++ b/src/it/gmariotti/cardslib/library/internal/CardHeader.java
@@ -167,6 +167,8 @@ public class CardHeader extends BaseCard {
*/
protected boolean mIsOverflowSelected=false;
+ private boolean couldUseNativeInnerLayout = false;
+
// -------------------------------------------------------------
// Constructors
// -------------------------------------------------------------
@@ -189,6 +191,9 @@ public class CardHeader extends BaseCard {
public CardHeader(Context context,int innerLayout) {
super(context);
mInnerLayout= innerLayout;
+
+ if (innerLayout == R.layout.inner_base_header)
+ couldUseNativeInnerLayout = true;
}
@@ -223,14 +228,6 @@ public class CardHeader extends BaseCard {
}
/**
- * Interface to handle callbacks when ExpandButton is clicked
- * Currently is never used
- */
- public interface OnClickExpandListener {
- public void onButtonExpandClick(BaseCard card, MenuItem item);
- }
-
- /**
* Interface to handle callbacks when Other Button is clicked
*/
public interface OnClickCardHeaderOtherButtonListener {
@@ -344,6 +341,10 @@ public class CardHeader extends BaseCard {
@Override
public View getInnerView(Context context, ViewGroup parent) {
+ //Check if the default inner layout could be the native layout
+ if (couldUseNativeInnerLayout && isNative())
+ mInnerLayout = R.layout.native_inner_base_header;
+
View view= super.getInnerView(context, parent);
//This provide a simple implementation with a single title
@@ -367,37 +368,22 @@ public class CardHeader extends BaseCard {
* This method sets values to header elements and customizes view.
*
* Override this method to set your elements inside InnerView.
- * If you use listviews it is recommend to user a Viewholder like here.
*
* @param parent parent view (Inner Frame)
* @param view Inner View
*/
@Override
- public void setupInnerViewElements(ViewGroup parent, View view) {
-
- // Add simple title to header
- if (view != null) {
- ViewHolder holder;
- holder = (ViewHolder) view.getTag();
-
- if (holder == null) {
- holder = new ViewHolder();
- holder.titleView =
- (TextView) view.findViewById(R.id.card_header_inner_simple_title);
- view.setTag(holder);
- }
+ public void setupInnerViewElements(ViewGroup parent,View view){
- if (holder.titleView != null) {
- holder.titleView.setText(mTitle);
- }
+ //Add simple title to header
+ if (view!=null){
+ TextView mTitleView=(TextView) view.findViewById(R.id.card_header_inner_simple_title);
+ if (mTitleView!=null)
+ mTitleView.setText(mTitle);
}
}
- static class ViewHolder {
- TextView titleView;
- }
-
// -------------------------------------------------------------
// Getters and Setters
// -------------------------------------------------------------
@@ -458,17 +444,11 @@ public class CardHeader extends BaseCard {
/**
* Indicates if overflow button is visible.
- * If the Popup Menu is =-1 return in any case <code>false</code>
*
- * @return <code>true</code> if the button is visible and Popup Menu is assigned.
+ * @return <code>true</code> if the button is visible
*/
public boolean isButtonOverflowVisible() {
- //Without a PopupMenu, the button is not visible
- if (mPopupMenu==NO_POPUP_MENU && mCustomOverflowAnimation==null){
- if (mIsButtonOverflowVisible)
- Log.w("CardHeader","You set visible=true to overflow menu, but you don't add any Popup Menu or a CustomOverflowAnimator");
- return false;
- }
+
return mIsButtonOverflowVisible;
}
@@ -556,5 +536,14 @@ public class CardHeader extends BaseCard {
mOtherButtonDrawable = otherButtonDrawable;
}
+ /**
+ * Returns true if the card is using the native card
+ * @return
+ */
+ protected boolean isNative(){
+ if (getParentCard() != null)
+ return getParentCard().isNative();
+ return false;
+ }
}
diff --git a/src/com/android/cards/internal/CardThumbnail.java b/src/it/gmariotti/cardslib/library/internal/CardThumbnail.java
index 30b7199..30b7199 100644
--- a/src/com/android/cards/internal/CardThumbnail.java
+++ b/src/it/gmariotti/cardslib/library/internal/CardThumbnail.java
diff --git a/src/com/android/cards/internal/ViewToClickToExpand.java b/src/it/gmariotti/cardslib/library/internal/ViewToClickToExpand.java
index 212b500..96a0ee8 100644
--- a/src/com/android/cards/internal/ViewToClickToExpand.java
+++ b/src/it/gmariotti/cardslib/library/internal/ViewToClickToExpand.java
@@ -50,6 +50,16 @@ public class ViewToClickToExpand {
*/
protected CardElementUI cardElementUIToClick;
+ /**
+ * Indicates the expand action will be used in programmatic way
+ */
+ protected boolean enableForCode = false;
+
+ /**
+ * Use the longClick to enable expand/collapse action
+ */
+ protected boolean useLongClick = false;
+
// -------------------------------------------------------------
// Constructors
// -------------------------------------------------------------
@@ -89,7 +99,7 @@ public class ViewToClickToExpand {
// -------------------------------------------------------------
/**
- * Sets the view to click to enable the expand/collpase action
+ * Sets the view to click to enable the expand/collapse action
*
* @param viewToClick view to click
* @return
@@ -115,12 +125,33 @@ public class ViewToClickToExpand {
return this;
}
+ /**
+ * Indicates if the expand action will be enabled in a programmatic way
+ *
+ * @return
+ */
+ public ViewToClickToExpand enableForExpandAction() {
+ this.enableForCode = true;
+ return this;
+ }
+
+ /**
+ * Indicates if the expand action will be enabled with a long click
+ *
+ * @return
+ */
+ public ViewToClickToExpand useLongClick(boolean useLongClick) {
+ this.useLongClick = useLongClick;
+ return this;
+ }
+
+
// -------------------------------------------------------------
// Getters
// -------------------------------------------------------------
/**
- * Returns the view to Click to enable the expand/collapse action
+ * Returns the view to Click to enable the expand action
* @return
*/
public View getViewToClick() {
@@ -143,5 +174,19 @@ public class ViewToClickToExpand {
return cardElementUIToClick;
}
+ /**
+ * Indicates if the expand action will be enabled in a programmatic way
+ * @return
+ */
+ public boolean isEnableForCode() {
+ return enableForCode;
+ }
+
+ /**
+ * Indicates if the expand action will be enabled with a long click
+ */
+ public boolean isUseLongClick() {
+ return useLongClick;
+ }
}
diff --git a/src/com/android/cards/internal/base/BaseCard.java b/src/it/gmariotti/cardslib/library/internal/base/BaseCard.java
index aae06dd..98eb26d 100644
--- a/src/com/android/cards/internal/base/BaseCard.java
+++ b/src/it/gmariotti/cardslib/library/internal/base/BaseCard.java
@@ -24,14 +24,14 @@ import android.view.View;
import android.view.ViewGroup;
import com.android.cards.internal.Card;
-import com.android.cards.view.CardView;
+import com.android.cards.view.base.CardViewWrapper;
/**
* Base Abstract Card model
*
* @author Gabriele Mariotti (gabri.mariotti@gmail.com)
*/
-public abstract class BaseCard implements CardUIInterface {
+public abstract class BaseCard implements CardUIInferface {
/**
* Context
@@ -46,7 +46,7 @@ public abstract class BaseCard implements CardUIInterface {
/**
* Outer View
*/
- protected CardView mCardView;
+ protected CardViewWrapper mCardView;
/**
* Inner View
@@ -92,7 +92,7 @@ public abstract class BaseCard implements CardUIInterface {
* @return the complete View component
*/
- public CardView getCardView() {
+ public CardViewWrapper getCardView() {
return mCardView;
}
@@ -170,10 +170,10 @@ public abstract class BaseCard implements CardUIInterface {
}
/**
- * Set the linked {@link CardView}
- * @param cardView {@link CardView}
+ * Set the linked {@link com.android.cards.view.base.CardViewWrapper}
+ * @param cardView {@link com.android.cards.view.base.CardViewWrapper}
*/
- public void setCardView(CardView cardView) {
+ public void setCardView(CardViewWrapper cardView) {
mCardView = cardView;
}
diff --git a/src/com/android/cards/internal/base/BaseCardArrayAdapter.java b/src/it/gmariotti/cardslib/library/internal/base/BaseCardArrayAdapter.java
index 3bf07a1..fd72911 100644
--- a/src/com/android/cards/internal/base/BaseCardArrayAdapter.java
+++ b/src/it/gmariotti/cardslib/library/internal/base/BaseCardArrayAdapter.java
@@ -26,7 +26,7 @@ import java.util.List;
import com.android.cards.R;
import com.android.cards.internal.Card;
-import com.android.cards.view.CardView;
+import com.android.cards.view.base.CardViewWrapper;
import com.android.cards.view.listener.UndoBarController;
/**
@@ -101,7 +101,7 @@ public abstract class BaseCardArrayAdapter extends ArrayAdapter<Card> {
* @param mCard
* @param mCardView
*/
- protected void setupMultichoice(View view,Card mCard,CardView mCardView,long position){
+ protected void setupMultichoice(View view,Card mCard,CardViewWrapper mCardView,long position){
//empty
}
diff --git a/src/com/android/cards/internal/base/BaseCardCursorAdapter.java b/src/it/gmariotti/cardslib/library/internal/base/BaseCardCursorAdapter.java
index e967ff6..dd57cca 100644
--- a/src/com/android/cards/internal/base/BaseCardCursorAdapter.java
+++ b/src/it/gmariotti/cardslib/library/internal/base/BaseCardCursorAdapter.java
@@ -20,10 +20,12 @@ package com.android.cards.internal.base;
import android.content.Context;
import android.database.Cursor;
+import android.view.View;
import android.widget.CursorAdapter;
import com.android.cards.R;
import com.android.cards.internal.Card;
+import com.android.cards.view.base.CardViewWrapper;
/**
* Base Cursor Adapter
@@ -93,6 +95,15 @@ public abstract class BaseCardCursorAdapter extends CursorAdapter {
return false;
}
+ /**
+ * This method is used in with multichoice
+ * @param mCard
+ * @param mCardView
+ */
+ protected void setupMultichoice(View view,Card mCard,CardViewWrapper mCardView,long position){
+ //empty
+ }
+
@Override
public Card getItem(int position) {
Object obj = super.getItem(position);
diff --git a/src/com/android/cards/internal/base/CardUIInterface.java b/src/it/gmariotti/cardslib/library/internal/base/CardUIInferface.java
index 9d62e9f..734ffc7 100644
--- a/src/com/android/cards/internal/base/CardUIInterface.java
+++ b/src/it/gmariotti/cardslib/library/internal/base/CardUIInferface.java
@@ -27,7 +27,7 @@ import android.view.ViewGroup;
*
* @author Gabriele Mariotti (gabri.mariotti@gmail.com)
*/
-public interface CardUIInterface {
+public interface CardUIInferface {
/**
* Implement this method to draw or inflate the Layout View of a Card or a Component Card.
diff --git a/src/com/android/cards/internal/dismissanimation/BaseDismissAnimation.java b/src/it/gmariotti/cardslib/library/internal/dismissanimation/BaseDismissAnimation.java
index f1e77b6..223864c 100644
--- a/src/com/android/cards/internal/dismissanimation/BaseDismissAnimation.java
+++ b/src/it/gmariotti/cardslib/library/internal/dismissanimation/BaseDismissAnimation.java
@@ -39,7 +39,7 @@ import com.android.cards.internal.Card;
import com.android.cards.internal.CardArrayAdapter;
import com.android.cards.internal.base.BaseCardArrayAdapter;
import com.android.cards.view.CardListView;
-import com.android.cards.view.CardView;
+import com.android.cards.view.base.CardViewWrapper;
import com.android.cards.view.listener.SwipeDismissListViewTouchListener;
/**
@@ -114,9 +114,9 @@ public abstract class BaseDismissAnimation {
prepareAnimation();
final List<Integer> positionsCopy = new ArrayList<Integer>(positions);
- List<CardView> views = getVisibleViewsForPositions(positionsCopy);
+ List<CardViewWrapper> views = getVisibleViewsForPositions(positionsCopy);
- for (CardView cardView:views){
+ for (CardViewWrapper cardView:views){
dismissiCardWithAnimation(cardView);
}
}
@@ -133,9 +133,9 @@ public abstract class BaseDismissAnimation {
prepareAnimation();
final List<Card> cardsCopy = new ArrayList<Card>(cards);
- List<CardView> views = getVisibleViewsForCards(cardsCopy);
+ List<CardViewWrapper> views = getVisibleViewsForCards(cardsCopy);
- for (CardView cardView:views){
+ for (CardViewWrapper cardView:views){
dismissiCardWithAnimation(cardView);
}
}
@@ -151,7 +151,7 @@ public abstract class BaseDismissAnimation {
}
- public abstract void animate(Card card, CardView cardView);//, Card.OnDismissAnimationListener onDismissAnimationListener);
+ public abstract void animate(Card card, CardViewWrapper cardView);//, Card.OnDismissAnimationListener onDismissAnimationListener);
/**
@@ -177,12 +177,12 @@ public abstract class BaseDismissAnimation {
* @param positions
* @return
*/
- private List<CardView> getVisibleViewsForPositions(final Collection<Integer> positions) {
- List<CardView> views = new ArrayList<CardView>();
+ private List<CardViewWrapper> getVisibleViewsForPositions(final Collection<Integer> positions) {
+ List<CardViewWrapper> views = new ArrayList<CardViewWrapper>();
for (int i = 0; i < mCardListView.getChildCount(); i++) {
View child = mCardListView.getChildAt(i);
if (positions.contains(mCardListView.getPositionForView(child))) {
- views.add((CardView) child);
+ views.add((CardViewWrapper) child);
}
}
return views;
@@ -194,8 +194,8 @@ public abstract class BaseDismissAnimation {
* @param cardsCopy
* @return
*/
- private List<CardView> getVisibleViewsForCards(List<Card> cardsCopy) {
- List<CardView> originalViews = new ArrayList<CardView>();
+ private List<CardViewWrapper> getVisibleViewsForCards(List<Card> cardsCopy) {
+ List<CardViewWrapper> originalViews = new ArrayList<CardViewWrapper>();
for (Card card:cardsCopy){
originalViews.add(card.getCardView());
}
@@ -210,9 +210,9 @@ public abstract class BaseDismissAnimation {
return originalViews;
}
- private void dismissiCardWithAnimation(final CardView cardView) {
+ private void dismissiCardWithAnimation(final CardViewWrapper cardView) {
++mDismissAnimationRefCount;
- int mDownPosition = mCardListView.getPositionForView(cardView);
+ int mDownPosition = mCardListView.getPositionForView((View)cardView);
animate(cardView.getCard(),cardView);
}
@@ -223,7 +223,7 @@ public abstract class BaseDismissAnimation {
// all dismissed list item animations have completed. This triggers layout on each animation
// frame; in the future we may want to do something smarter and more performant.
- final int dismissPosition= mBaseAdapter.getPosition(((CardView) dismissView).getCard());
+ final int dismissPosition= mBaseAdapter.getPosition(((CardViewWrapper) dismissView).getCard());
final ViewGroup.LayoutParams lp = dismissView.getLayoutParams();
final int originalHeight = dismissView.getHeight();
diff --git a/src/com/android/cards/internal/dismissanimation/SwipeDismissAnimation.java b/src/it/gmariotti/cardslib/library/internal/dismissanimation/SwipeDismissAnimation.java
index 3b6705d..0332855 100644
--- a/src/com/android/cards/internal/dismissanimation/SwipeDismissAnimation.java
+++ b/src/it/gmariotti/cardslib/library/internal/dismissanimation/SwipeDismissAnimation.java
@@ -21,9 +21,10 @@ package com.android.cards.internal.dismissanimation;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
+import android.view.View;
import com.android.cards.internal.Card;
-import com.android.cards.view.CardView;
+import com.android.cards.view.base.CardViewWrapper;
/**
* @author Gabriele Mariotti (gabri.mariotti@gmail.com)
@@ -42,16 +43,16 @@ public class SwipeDismissAnimation extends BaseDismissAnimation {
}
@Override
- public void animate(final Card card, final CardView cardView) {
+ public void animate(final Card card, final CardViewWrapper cardView) {
- cardView.animate()
+ ((View)cardView).animate()
.translationX(mDismissRight ? mListWidth : -mListWidth)
.alpha(0)
.setDuration(mAnimationTime)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- invokeCallbak(cardView);
+ invokeCallbak((View)cardView);
}
});
}
diff --git a/src/com/android/cards/internal/multichoice/DefaultOptionMultiChoice.java b/src/it/gmariotti/cardslib/library/internal/multichoice/DefaultOptionMultiChoice.java
index 5424693..5424693 100644
--- a/src/com/android/cards/internal/multichoice/DefaultOptionMultiChoice.java
+++ b/src/it/gmariotti/cardslib/library/internal/multichoice/DefaultOptionMultiChoice.java
diff --git a/src/com/android/cards/internal/multichoice/MultiChoiceAdapter.java b/src/it/gmariotti/cardslib/library/internal/multichoice/MultiChoiceAdapter.java
index 9628d78..16422d0 100644
--- a/src/com/android/cards/internal/multichoice/MultiChoiceAdapter.java
+++ b/src/it/gmariotti/cardslib/library/internal/multichoice/MultiChoiceAdapter.java
@@ -21,7 +21,8 @@ package com.android.cards.internal.multichoice;
import android.view.ActionMode;
import com.android.cards.internal.Card;
-import com.android.cards.view.CardView;
+import com.android.cards.view.base.CardViewWrapper;
+
/**
* A base interface for multi choice adapter
@@ -63,9 +64,7 @@ public interface MultiChoiceAdapter {
* @param cardView
* @param card
*/
- void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked, CardView cardView, Card card);
-
-
+ void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked, CardViewWrapper cardView, Card card);
// -------------------------------------------------------------
// Default methods. You haven't to define it in your classes
diff --git a/src/com/android/cards/internal/multichoice/MultiChoiceAdapterHelperBase.java b/src/it/gmariotti/cardslib/library/internal/multichoice/MultiChoiceAdapterHelperBase.java
index 922f8eb..0f1d9d1 100644
--- a/src/com/android/cards/internal/multichoice/MultiChoiceAdapterHelperBase.java
+++ b/src/it/gmariotti/cardslib/library/internal/multichoice/MultiChoiceAdapterHelperBase.java
@@ -37,7 +37,7 @@ import java.util.ArrayList;
import com.android.cards.R;
import com.android.cards.internal.Card;
-import com.android.cards.view.CardView;
+import com.android.cards.view.base.CardViewWrapper;
public class MultiChoiceAdapterHelperBase implements AdapterView.OnItemLongClickListener,AdapterView.OnItemClickListener {
@@ -84,14 +84,14 @@ public class MultiChoiceAdapterHelperBase implements AdapterView.OnItemLongClick
* @param mCardView
* @param position
*/
- public void setupMultichoice(View view, Card mCard, CardView mCardView, long position) {
+ public void setupMultichoice(View view, Card mCard, CardViewWrapper mCardView, long position) {
final MultiChoiceAdapter adapter = (MultiChoiceAdapter) owner;
View.OnClickListener advanceClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
- final CardView cardView = (CardView) v;
+ final CardViewWrapper cardView = (CardViewWrapper) v;
int position = adapter.getPosition(cardView.getCard());
onItemClick(mAdapterView, v, position, adapter.getItemId(position));
}
@@ -355,4 +355,4 @@ public class MultiChoiceAdapterHelperBase implements AdapterView.OnItemLongClick
mMultiChoiceModeListener = multiChoiceModeListener;
}
-}
+} \ No newline at end of file
diff --git a/src/com/android/cards/internal/multichoice/OptionMultiChoice.java b/src/it/gmariotti/cardslib/library/internal/multichoice/OptionMultiChoice.java
index d6c9f33..d6c9f33 100644
--- a/src/com/android/cards/internal/multichoice/OptionMultiChoice.java
+++ b/src/it/gmariotti/cardslib/library/internal/multichoice/OptionMultiChoice.java
diff --git a/src/it/gmariotti/cardslib/library/prototypes/CardSection.java b/src/it/gmariotti/cardslib/library/prototypes/CardSection.java
new file mode 100644
index 0000000..c305a70
--- /dev/null
+++ b/src/it/gmariotti/cardslib/library/prototypes/CardSection.java
@@ -0,0 +1,47 @@
+/*
+ * ******************************************************************************
+ * Copyright (c) 2013-2014 Gabriele Mariotti.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * *****************************************************************************
+ */
+
+package com.android.cards.prototypes;
+
+/**
+ * Default card section
+ * @author Gabriele Mariotti (gabri.mariotti@gmail.com)
+ */
+public class CardSection {
+
+ int firstPosition;
+ int sectionedPosition;
+ CharSequence title;
+
+ // -------------------------------------------------------------
+ // Constructor
+ // -------------------------------------------------------------
+
+ public CardSection(int firstPosition, CharSequence title) {
+ this.firstPosition = firstPosition;
+ this.title = title;
+ }
+
+ /**
+ *
+ * @return the title
+ */
+ public CharSequence getTitle() {
+ return title;
+ }
+} \ No newline at end of file
diff --git a/src/it/gmariotti/cardslib/library/prototypes/CardWithList.java b/src/it/gmariotti/cardslib/library/prototypes/CardWithList.java
new file mode 100644
index 0000000..38f8013
--- /dev/null
+++ b/src/it/gmariotti/cardslib/library/prototypes/CardWithList.java
@@ -0,0 +1,1027 @@
+/*
+ * ******************************************************************************
+ * Copyright (c) 2013-2014 Gabriele Mariotti.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * *****************************************************************************
+ */
+
+package com.android.cards.prototypes;
+
+import android.content.Context;
+import android.database.DataSetObserver;
+import android.view.LayoutInflater;
+import android.view.SoundEffectConstants;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewStub;
+import android.view.animation.AnimationUtils;
+import android.widget.ArrayAdapter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.android.cards.R;
+import com.android.cards.internal.Card;
+import com.android.cards.internal.CardHeader;
+
+/**
+ * A card with a LinearList inside.
+ * It is a particular Card that can display items inside the Card.
+ *
+ * @author Gabriele Mariotti (gabri.mariotti@gmail.com)
+ */
+@SuppressWarnings({"JavaDoc", "UnusedDeclaration"})
+public abstract class CardWithList extends Card {
+
+ /**
+ * The cardHeader
+ */
+ protected CardHeader mCardHeader;
+
+ /**
+ * The "listView"
+ */
+ protected LinearListView mListView;
+
+ /**
+ * The listAdapter
+ */
+ protected LinearListAdapter mLinearListAdapter;
+
+ /**
+ * Default layout used for each row
+ */
+ protected int mChildLayoutId;
+
+ /**
+ * Empty View
+ */
+ private View mEmptyView;
+
+ /**
+ * Progress View
+ */
+ private View mProgressView;
+
+ /**
+ * Resource Id used which identifies the empty view
+ */
+ protected int emptyViewId = R.id.card_inner_base_empty_cardwithlist;
+
+ /**
+ * An identifier for the layout resource to inflate when the ViewStub becomes visible
+ */
+ protected int emptyViewViewStubLayoutId = R.layout.base_withlist_empty;
+
+ /**
+ * Resource Id used which identifies the progressBar
+ */
+ protected int progressBarId = R.id.card_inner_base_progressbar_cardwithlist;
+
+
+ /**
+ * An identifier for the layout resource to inflate when the ViewStub becomes visible
+ */
+ protected int progressBarViewStubLayoutId = R.layout.base_withlist_progress;
+
+ /**
+ * Indicates if the empty view feature is enabled
+ */
+ protected boolean useEmptyView = true;
+
+ /**
+ * Indicates if the progressBar feature is enabled
+ */
+ protected boolean useProgressBar = false;
+
+ /**
+ * Internal flag to indicate if the list is shown
+ */
+ private boolean mListShown;
+
+ /**
+ * Resource Id used which identifies the list
+ */
+ protected int listViewId = R.id.card_inner_base_main_cardwithlist;
+
+ /**
+ * Flag to set the observer as registered
+ */
+ private boolean observerRegistered = false;
+
+ private boolean couldUseNativeInnerLayout = false;
+
+
+ private DataSetObserver mDataObserver = new DataSetObserver() {
+
+ @Override
+ public void onChanged() {
+ internalSetupChildren();
+ }
+
+ @Override
+ public void onInvalidated() {
+ internalSetupChildren();
+ }
+
+ };
+
+ // -------------------------------------------------------------
+ // Constructors
+ // -------------------------------------------------------------
+
+ /**
+ * Constructor with a base inner layout defined by R.layout.inner_base_main_cardwithlist
+ *
+ * @param context context
+ */
+ public CardWithList(Context context) {
+ this(context, R.layout.inner_base_main_cardwithlist);
+ }
+
+ /**
+ * Constructor with a custom inner layout.
+ *
+ * @param context context
+ * @param innerLayout resource ID for inner layout
+ */
+ public CardWithList(Context context, int innerLayout) {
+ super(context, innerLayout);
+
+ if (innerLayout == R.layout.inner_base_main_cardwithlist) {
+ couldUseNativeInnerLayout = true;
+ }
+ }
+
+ // -------------------------------------------------------------
+ // Init
+ // -------------------------------------------------------------
+
+ /**
+ * Init the card
+ */
+ public void init() {
+
+ //Init the CardHeader
+ mCardHeader = initCardHeader();
+ if (mCardHeader != null)
+ addCardHeader(mCardHeader);
+
+ //Init the Card
+ initCard();
+
+ //Init the children
+ List<ListObject> mChildren = initChildren();
+ if (mChildren == null)
+ mChildren = new ArrayList<ListObject>();
+ mLinearListAdapter = new LinearListAdapter(super.getContext(), mChildren);
+
+ //Retrieve the layoutId use by children
+ mChildLayoutId = getChildLayoutId();
+
+ }
+
+ // -------------------------------------------------------------
+ // Abstract method to be implemented in your class
+ // -------------------------------------------------------------
+
+ /**
+ * Implement this method to initialize your CardHeader.
+ * <p/>
+ * An example:
+ * <pre><code>
+ * //Add Header
+ * CardHeader header = new CardHeader(getContext());
+ * //Add a popup menu. This method set OverFlow button to visible
+ * header.setPopupMenu(R.menu.popupmain, new CardHeader.OnClickCardHeaderPopupMenuListener() {
+ * @Override
+ * public void onMenuItemClick(BaseCard card, MenuItem item) {
+ * Toast.makeText(getContext(), "Click on " + item.getTitle(), Toast.LENGTH_SHORT).show();
+ * }
+ * });
+ * header.setTitle("Weather"); //should use R.string.
+ * return header;
+ * <p/>
+ * </code></pre>
+ *
+ * @return the {@link CardHeader}
+ */
+ protected abstract CardHeader initCardHeader();
+
+ /**
+ * Implement this method to initialize your Card.
+ * <p/>
+ * An example:
+ * <pre><code>
+ * setSwipeable(true);
+ * setOnSwipeListener(new OnSwipeListener() {
+ * @Override
+ * public void onSwipe(Card card) {
+ * Toast.makeText(getContext(), "Swipe on " + card.getCardHeader().getTitle(), Toast.LENGTH_SHORT).show();
+ * }
+ * });
+ * </code></pre>
+ */
+ protected abstract void initCard();
+
+ /**
+ * Implement this method to initialize the list of objects
+ * <p/>
+ * An example:
+ * <pre><code>
+ * <p/>
+ * List<ListObject> mObjects = new ArrayList<ListObject>();
+ * <p/>
+ * WeatherObject w1= new WeatherObject();
+ * mObjects.add(w1);
+ * <p/>
+ * return mObjects;
+ * </code></pre>
+ *
+ * @return the List of ListObject. Return <code>null</code> if the list is empty.
+ */
+ protected abstract List<ListObject> initChildren();
+
+ /**
+ * This method is called by the {@link com.android.cards.prototypes.CardWithList.LinearListAdapter} for each row.
+ * You can provide your layout and setup your ui elements.
+ *
+ * @param childPosition position inside the list of objects
+ * @param object {@link com.android.cards.prototypes.CardWithList.ListObject}
+ * @param convertView view used by row
+ * @param parent parent view
+ * @return
+ */
+ public abstract View setupChildView(int childPosition, ListObject object, View convertView, ViewGroup parent);
+
+ /**
+ * Implement this method to specify the layoutId used for each row in the list
+ *
+ * @return the layoutId
+ */
+ public abstract int getChildLayoutId();
+
+
+ // -------------------------------------------------------------
+ // View
+ // -------------------------------------------------------------
+
+ /**
+ * Returns the id that identifies the {@link LinearListView}.
+ *
+ * @return
+ */
+ protected int getListViewId() {
+ return listViewId;
+ }
+
+ @Override
+ protected void setupInnerLayout() {
+ //Check if the default inner layout could be the native layout
+ if (couldUseNativeInnerLayout && isNative())
+ mInnerLayout = R.layout.native_inner_base_main_cardwithlist;
+ }
+
+ /**
+ * Setup the listAdapter.
+ *
+ * @param parent parent view (Inner Frame)
+ * @param view Inner View
+ */
+ @Override
+ public void setupInnerViewElements(ViewGroup parent, View view) {
+
+ mListView = (LinearListView) view.findViewById(getListViewId());
+ if (mListView != null) {
+
+ internalSetupProgressBar(parent, view);
+
+ if (mLinearListAdapter != null) {
+ internalSetupChildren();
+ mLinearListAdapter.registerDataSetObserver(mDataObserver);
+ }
+ }
+
+ internalSetupEmptyView(parent, view);
+
+ }
+
+ /**
+ * Setup the children
+ */
+ private void internalSetupChildren() {
+ if (mListView != null) {
+
+ mListView.removeAllViews();
+
+ updateEmptyStatus((mLinearListAdapter == null) || mLinearListAdapter.isEmpty());
+
+ if (mLinearListAdapter == null) {
+ return;
+ }
+ mListView.setAdapter(mLinearListAdapter);
+ }
+ }
+
+ /**
+ * Setup the empty view.
+ *
+ * @param parent mainContentLayout
+ * @param view innerView
+ */
+ @SuppressWarnings("UnusedParameters")
+ private void internalSetupEmptyView(ViewGroup parent, View view) {
+ if (useEmptyView) {
+ mEmptyView = (View) parent.findViewById(getEmptyViewId());
+ if (mEmptyView != null) {
+ if (mEmptyView instanceof ViewStub)
+ ((ViewStub) mEmptyView).setLayoutResource(getEmptyViewViewStubLayoutId());
+ setEmptyView(mEmptyView);
+ }
+ }
+ }
+
+ /**
+ * Setup the Progress Bar view.
+ *
+ * @param parent mainContentLayout
+ * @param view innerView
+ */
+ @SuppressWarnings("UnusedParameters")
+ private void internalSetupProgressBar(ViewGroup parent, View view) {
+ if (useProgressBar) {
+ mProgressView = (View) parent.findViewById(getProgressBarId());
+ mListShown=true;
+ if (mProgressView != null) {
+ if (mProgressView instanceof ViewStub)
+ ((ViewStub) mProgressView).setLayoutResource(getProgressBarViewStubLayoutId());
+ setProgressView(mProgressView);
+ }
+ }
+ }
+
+ /**
+ * Use this method to unregister the observer
+ */
+ public void unregisterDataSetObserver(){
+ if (mLinearListAdapter!=null)
+ mLinearListAdapter.unregisterDataSetObserver(mDataObserver);
+ }
+
+ // -------------------------------------------------------------
+ // Interface to be used by children
+ // -------------------------------------------------------------
+
+
+ /**
+ * Children have to implement this interface
+ */
+ public interface ListObject {
+
+ /**
+ * Returns the object id
+ *
+ * @return
+ */
+ public String getObjectId();
+
+ /**
+ * Returns the parent card
+ */
+ public Card getParentCard();
+
+ /**
+ * Register a callback to be invoked when an item in this LinearListView has
+ * been clicked.
+ *
+ * @return The callback to be invoked with an item in this LinearListView has
+ * been clicked, or null id no callback has been set.
+ */
+ public void setOnItemClickListener(OnItemClickListener onItemClickListener);
+
+ /**
+ * @return The callback to be invoked with an item in this LinearListView has
+ * been clicked, or null id no callback has been set.
+ */
+ public OnItemClickListener getOnItemClickListener();
+
+ /**
+ * Indicates if the item is swipeable
+ */
+ public boolean isSwipeable();
+
+ /**
+ * Set the item as swipeable
+ *
+ * @param isSwipeable
+ */
+ public void setSwipeable(boolean isSwipeable);
+
+ /**
+ * Returns the callback to be invoked when item has been swiped
+ *
+ * @return listener
+ */
+ public OnItemSwipeListener getOnItemSwipeListener();
+
+ /**
+ * Register a callback to be invoked when an item in this LinearListView has
+ * been swiped.
+ *
+ * @param onSwipeListener listener
+ */
+ public void setOnItemSwipeListener(OnItemSwipeListener onSwipeListener);
+
+ }
+
+
+ // -------------------------------------------------------------
+ // Interface definition for a callback to be invoked when an item in this
+ // LinearListView has been clicked.
+ // -------------------------------------------------------------
+
+ /**
+ * Interface definition for a callback to be invoked when an item in this
+ * LinearListView has been clicked.
+ */
+ public interface OnItemClickListener {
+
+ /**
+ * Callback method to be invoked when an item in this LinearListView has
+ * been clicked.
+ * <p/>
+ * Implementers can call getItemAtPosition(position) if they need to
+ * access the data associated with the selected item.
+ *
+ * @param parent The LinearListView where the click happened.
+ * @param view The view within the LinearListView that was clicked (this
+ * will be a view provided by the adapter)
+ * @param position The position of the view in the adapter.
+ * @param object The object that was clicked.
+ */
+ void onItemClick(LinearListView parent, View view, int position, ListObject object);
+ }
+
+ // -------------------------------------------------------------
+ // On Item Swipe Interface
+ // -------------------------------------------------------------
+
+ /**
+ * Interface definition for a callback to be invoked when an item in this
+ * LinearListView has been swiped
+ */
+ public interface OnItemSwipeListener {
+
+ /**
+ * Callback method to be invoked when an item in this LinearListView has
+ * been swiped.
+ *
+ * @param object The object that was clicked.
+ */
+ public void onItemSwipe(ListObject object,boolean dismissRight);
+
+ }
+
+
+ /**
+ * Returns listener invoked when card is swiped
+ *
+ * @return listener
+ */
+ public OnSwipeListener getOnSwipeListener() {
+ return mOnSwipeListener;
+ }
+
+ /**
+ * Sets listener invoked when card is swiped.
+ * If listener is <code>null</code> the card is not swipeable.
+ *
+ * @param onSwipeListener listener
+ */
+ public void setOnSwipeListener(OnSwipeListener onSwipeListener) {
+ if (onSwipeListener != null)
+ mIsSwipeable = true;
+ else
+ mIsSwipeable = false;
+ this.mOnSwipeListener = onSwipeListener;
+ }
+
+ // -------------------------------------------------------------
+ // Default Implementation for ListObject
+ // -------------------------------------------------------------
+
+ /**
+ * Default ListObject
+ */
+ public class DefaultListObject implements ListObject {
+
+ /**
+ * Object Id
+ */
+ protected String mObjectId;
+
+ /**
+ * Parent Card
+ */
+ protected Card mParentCard;
+
+ /*
+ * Item click listener
+ */
+ protected OnItemClickListener mOnItemClickListener;
+
+ /**
+ *
+ */
+ protected boolean mItemSwipeable = false;
+
+ /**
+ * Item swipe listener
+ */
+ protected OnItemSwipeListener mOnItemSwipeListener;
+
+ // -------------------------------------------------------------
+ // Constructor
+ // -------------------------------------------------------------
+ public DefaultListObject(Card parentCard) {
+ this.mParentCard = parentCard;
+ }
+
+ // -------------------------------------------------------------
+ // Default Implementation for getters and setters
+ // -------------------------------------------------------------
+
+ @Override
+ public String getObjectId() {
+ return mObjectId;
+ }
+
+ @Override
+ public Card getParentCard() {
+ return null;
+ }
+
+ public void setObjectId(String objectId) {
+ mObjectId = objectId;
+ }
+
+
+ @Override
+ public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
+ mOnItemClickListener = onItemClickListener;
+ }
+
+ @Override
+ public OnItemClickListener getOnItemClickListener() {
+ return mOnItemClickListener;
+ }
+
+ @Override
+ public boolean isSwipeable() {
+ return mItemSwipeable;
+ }
+
+ @Override
+ public void setSwipeable(boolean isSwipeable) {
+ mItemSwipeable = isSwipeable;
+ }
+
+ @Override
+ public OnItemSwipeListener getOnItemSwipeListener() {
+ return mOnItemSwipeListener;
+ }
+
+ @Override
+ public void setOnItemSwipeListener(OnItemSwipeListener onItemSwipeListener) {
+ if (onItemSwipeListener != null)
+ mItemSwipeable = true;
+ else
+ mItemSwipeable = false;
+ this.mOnItemSwipeListener = onItemSwipeListener;
+ }
+
+
+ }
+
+ // -------------------------------------------------------------
+ // Empty View
+ // -------------------------------------------------------------
+
+ /**
+ * Sets the view to show if the adapter is empty
+ */
+ public void setEmptyView(View emptyView) {
+ mEmptyView = emptyView;
+
+ useEmptyView = emptyView != null ? true : false;
+
+ final LinearListAdapter adapter = getLinearListAdapter();
+ final boolean empty = ((adapter == null) || adapter.isEmpty());
+ updateEmptyStatus(empty);
+ }
+
+ /**
+ * When the current adapter is empty, the LinearListView can display a special
+ * view call the empty view. The empty view is used to provide feedback to
+ * the user that no data is available in this LinearListView.
+ *
+ * @return The view to show if the adapter is empty.
+ */
+ public View getEmptyView() {
+ return mEmptyView;
+ }
+
+ /**
+ * Update the status of the list based on the empty parameter. If empty is
+ * true and we have an empty view, display it. In all the other cases, make
+ * sure that the layout is VISIBLE and that the empty view is GONE (if
+ * it's not null).
+ */
+ private void updateEmptyStatus(boolean empty) {
+ if (isUseEmptyView()) {
+ if (empty) {
+ if (mEmptyView != null) {
+ mEmptyView.setVisibility(View.VISIBLE);
+ mListView.setVisibility(View.GONE);
+ } else {
+ // If the caller just removed our empty view, make sure the list
+ // view is visible
+ mListView.setVisibility(View.VISIBLE);
+ }
+ } else {
+ if (mEmptyView != null)
+ mEmptyView.setVisibility(View.GONE);
+ mListView.setVisibility(View.VISIBLE);
+ }
+ }
+ }
+
+
+
+ // -------------------------------------------------------------
+ // Progress bar
+ // -------------------------------------------------------------
+
+ /**
+ * When the current adapter is loading data, the LinearListView can display a special
+ * progress Bar.
+ *
+ * @return The view to show if the adapter is the progress bar is enabled.
+ */
+ public View getProgressView() {
+ return mProgressView;
+ }
+
+ /**
+ * Sets the view to show as progress bar
+ */
+ public void setProgressView(View progressView) {
+ mProgressView = progressView;
+ useProgressBar = progressView != null;
+ }
+
+ /**
+ * Updates the status of the list and the progress bar.
+ *
+ * @param shownList indicates if the list has to be shown
+ * @param animate indicates to use an animation between view transition
+ */
+ public void updateProgressBar(boolean shownList, boolean animate) {
+ if (isUseProgressBar()) {
+ if (mListShown == shownList) {
+ return;
+ }
+ mListShown = shownList;
+
+ if (shownList) {
+ if (animate) {
+ mProgressView.startAnimation(AnimationUtils.loadAnimation(
+ getContext(), android.R.anim.fade_out));
+ mListView.startAnimation(AnimationUtils.loadAnimation(
+ getContext(), android.R.anim.fade_in));
+ if (useEmptyView && mEmptyView!=null){
+ mEmptyView.startAnimation(AnimationUtils.loadAnimation(
+ getContext(), android.R.anim.fade_in));
+ }
+ }
+ mProgressView.setVisibility(View.GONE);
+
+ final LinearListAdapter adapter = getLinearListAdapter();
+ final boolean empty = ((adapter == null) || adapter.isEmpty());
+ updateEmptyStatus(empty);
+
+
+ } else {
+ if (animate) {
+ mProgressView.startAnimation(AnimationUtils.loadAnimation(
+ getContext(), android.R.anim.fade_in));
+ mListView.startAnimation(AnimationUtils.loadAnimation(
+ getContext(), android.R.anim.fade_out));
+ if (useEmptyView && mEmptyView!=null){
+ mEmptyView.startAnimation(AnimationUtils.loadAnimation(
+ getContext(), android.R.anim.fade_out));
+ }
+ }
+ mProgressView.setVisibility(View.VISIBLE);
+ mListView.setVisibility(View.INVISIBLE);
+ if (useEmptyView && mEmptyView!=null){
+ mEmptyView.setVisibility(View.INVISIBLE);
+ }
+ }
+ }
+ }
+
+ // -------------------------------------------------------------
+ // Internal Adapter
+ // -------------------------------------------------------------
+
+ /**
+ * ListAdapter used to populate the LinearLayout inside the Card.
+ */
+ @SuppressWarnings("JavaDoc")
+ protected class LinearListAdapter extends ArrayAdapter<ListObject> {
+
+ LayoutInflater mLayoutInflater;
+
+ /**
+ * Listener invoked when a card is swiped
+ */
+ protected SwipeDismissListItemViewTouchListener mOnTouchListener;
+
+ /**
+ * Constructor
+ *
+ * @param context context
+ * @param objects objects
+ */
+ public LinearListAdapter(Context context, List<ListObject> objects) {
+ super(context, 0, objects);
+ //mObjects = objects;
+ mLayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ }
+
+ @Override
+ public View getView(final int position, View convertView, ViewGroup parent) {
+
+ //Object
+ final ListObject object = getItem(position);
+
+ View view = convertView;
+ if (view == null) {
+ view = mLayoutInflater.inflate(getChildLayoutId(), parent, false);
+ }
+
+ //Setup the elements
+ final View viewChild = setupChildView(position, object, view, parent);
+
+ //ClickItem Listener
+ if (viewChild != null && object.getOnItemClickListener() != null) {
+ view.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mListView.playSoundEffect(SoundEffectConstants.CLICK);
+ object.getOnItemClickListener().onItemClick(mListView, viewChild, position, object);
+ }
+ });
+ }
+
+ //SwipeItem Listener
+ setupItemSwipeAnimation(object, viewChild);
+
+ return viewChild;
+ }
+
+
+ @Override
+ public int getViewTypeCount() {
+ return 1;
+ }
+
+ /**
+ * Sets SwipeAnimation on items List
+ *
+ * @param item {@link ListObject}
+ * @param itemView itemView
+ */
+ protected void setupItemSwipeAnimation(final ListObject item, View itemView) {
+
+ if (item.isSwipeable()) {
+ if (mOnTouchListener == null) {
+ mOnTouchListener = new SwipeDismissListItemViewTouchListener(mListView, mCallback);
+ }
+ itemView.setOnTouchListener(mOnTouchListener);
+ }
+ }
+
+
+ /**
+ * Returns the Object Id
+ *
+ * @param position position in the list
+ * @return the object Id
+ */
+ @SuppressWarnings("UnusedDeclaration")
+ public String getChildId(int position) {
+ //Object
+ ListObject object = getItem(position);
+ return object.getObjectId();
+ }
+
+
+ // -------------------------------------------------------------
+ // SwipeListener and undo action
+ // -------------------------------------------------------------
+ /**
+ * Listener invoked when a card is swiped
+ */
+ SwipeDismissListItemViewTouchListener.DismissCallbacks mCallback = new SwipeDismissListItemViewTouchListener.DismissCallbacks() {
+ @Override
+ public boolean canDismiss(int position, Card card, ListObject listObject) {
+ return listObject.isSwipeable();
+ }
+
+ @Override
+ public void onDismiss(LinearListView listView, int position, boolean dismissRight) {
+
+ int i = 0;
+
+ //Remove cards and notifyDataSetChanged
+ ListObject object = getItem(position);
+ remove(object);
+ if (object.getOnItemSwipeListener() != null) {
+ object.getOnItemSwipeListener().onItemSwipe(object,dismissRight);
+ }
+ }
+ };
+
+ @Override
+ public void registerDataSetObserver(DataSetObserver observer) {
+ if (!observerRegistered) {
+ super.registerDataSetObserver(observer);
+ }
+ observerRegistered = true;
+ }
+
+ @Override
+ public void unregisterDataSetObserver(DataSetObserver observer) {
+ if (observer == null) {
+ observerRegistered = false;
+ return;
+ }
+ super.unregisterDataSetObserver(observer);
+ observerRegistered = false;
+ }
+ }
+
+ // -------------------------------------------------------------
+ // Getter and setter
+ // -------------------------------------------------------------
+
+ /**
+ * Returns the adapter
+ *
+ * @return the adapter
+ */
+ public LinearListAdapter getLinearListAdapter() {
+ return mLinearListAdapter;
+ }
+
+ /**
+ * Sets the adapter
+ *
+ * @param linearListAdapter adapter
+ */
+ public void setLinearListAdapter(LinearListAdapter linearListAdapter) {
+ mLinearListAdapter = linearListAdapter;
+ }
+
+ /**
+ * Returns the resource Id used which identifies the empty view
+ *
+ * @return the resource Id used which identifies the empty view
+ */
+ public int getEmptyViewId() {
+ return emptyViewId;
+ }
+
+ /**
+ * Sets the resource Id used which identifies the empty view
+ *
+ * @param emptyViewId resource Id used which identifies the empty view
+ */
+ public void setEmptyViewId(int emptyViewId) {
+ this.emptyViewId = emptyViewId;
+ }
+
+ /**
+ * Returns the resource Id used which identifies the ProgressBar
+ * @return the resource Id used which identifies the ProgressBar
+ */
+ public int getProgressBarId() {
+ return progressBarId;
+ }
+
+ /**
+ * Sets the resource Id used which identifies the ProgressBar
+ * @param progressBarId resource Id used which identifies the ProgressBar
+ */
+ public void setProgressBarId(int progressBarId) {
+ this.progressBarId = progressBarId;
+ }
+
+ /**
+ * Return if the card uses the empty view built-in feature
+ *
+ * @return true if the card uses the empty view
+ */
+ private boolean isUseEmptyView() {
+ if (mEmptyView != null)
+ return useEmptyView;
+ else return false;
+ }
+
+ /**
+ * Sets the flag to enable and disable the empty view feature
+ *
+ * @param useEmptyView flag
+ */
+ public void setUseEmptyView(boolean useEmptyView) {
+ this.useEmptyView = useEmptyView;
+ }
+
+ private boolean isUseProgressBar() {
+ if (mProgressView != null)
+ return useProgressBar;
+ else
+ return false;
+ }
+
+ /**
+ * Sets the flag to enable and disable the progress bar
+ * @param useProgressBar
+ */
+ public void setUseProgressBar(boolean useProgressBar) {
+ this.useProgressBar = useProgressBar;
+ }
+
+
+ /**
+ * Sets the resource Id used which identifies the list
+ *
+ * @param listViewId resourceId which identifies the list
+ */
+ public void setListViewId(int listViewId) {
+ this.listViewId = listViewId;
+ }
+
+ /**
+ * Returns the identifier for the layout resource to inflate when the ViewStub becomes visible
+ * It is used only if the {@see useEmptyView) is setted to true and the {@see mEmptyView} is a {@link android.view.ViewStub}.
+ *
+ * @return
+ */
+ public int getEmptyViewViewStubLayoutId() {
+ return emptyViewViewStubLayoutId;
+ }
+
+ /**
+ * Sets the identifier for the layout resource to inflate when the ViewStub becomes visible
+ *
+ * @param emptyViewViewStubLayoutId
+ */
+ public void setEmptyViewViewStubLayoutId(int emptyViewViewStubLayoutId) {
+ this.emptyViewViewStubLayoutId = emptyViewViewStubLayoutId;
+ }
+
+ /**
+ * Returns the identifier for the layout resource to inflate when the ViewStub used by the ProgressBar becomes visible
+ * It is used only if the {@see useProgressBar) is setted to true and the {@see mProgressView} is a {@link android.view.ViewStub}.
+ *
+ * @return
+ */
+ public int getProgressBarViewStubLayoutId() {
+ return progressBarViewStubLayoutId;
+ }
+
+ /**
+ * Sets the identifier for the layout resource to inflate when the ViewStub used by the ProgressBar becomes visible
+ *
+ * @param progressBarViewStubLayoutId
+ */
+ public void setProgressBarViewStubLayoutId(int progressBarViewStubLayoutId) {
+ this.progressBarViewStubLayoutId = progressBarViewStubLayoutId;
+ }
+}
+
+
diff --git a/src/it/gmariotti/cardslib/library/prototypes/LinearListView.java b/src/it/gmariotti/cardslib/library/prototypes/LinearListView.java
new file mode 100644
index 0000000..3244135
--- /dev/null
+++ b/src/it/gmariotti/cardslib/library/prototypes/LinearListView.java
@@ -0,0 +1,383 @@
+/*
+ * ******************************************************************************
+ * Copyright (c) 2013-2014 Gabriele Mariotti.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * *****************************************************************************
+ */
+
+package com.android.cards.prototypes;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import com.android.cards.R;
+
+/**
+ * An extension of a linear layout that supports the divider API of Android
+ * 4.0+. You can populate this layout with data that comes from a
+ * {@link android.widget.ListAdapter}
+ *
+ * @author Gabriele Mariotti (gabri.mariotti@gmail.com)
+ */
+public class LinearListView extends LinearLayout {
+
+ /**
+ * Adapter
+ */
+ private CardWithList.LinearListAdapter mListAdapter;
+
+ /**
+ * Represents an invalid position. All valid positions are in the range 0 to 1 less than the
+ * number of items in the current adapter.
+ */
+ public static final int INVALID_POSITION = -1;
+
+ // -------------------------------------------------------------
+ // Constructors
+ // -------------------------------------------------------------
+
+ public LinearListView(Context context) {
+ super(context);
+ initAttrs(null, 0);
+ }
+
+ public LinearListView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ initAttrs(attrs, 0);
+ }
+
+ public LinearListView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ initAttrs(attrs, defStyle);
+ }
+
+ // -------------------------------------------------------------
+ // Init
+ // -------------------------------------------------------------
+
+ /**
+ * Init custom attrs.
+ *
+ * @param attrs
+ * @param defStyle
+ */
+ protected void initAttrs(AttributeSet attrs, int defStyle) {
+
+ TypedArray a = getContext().getTheme().obtainStyledAttributes(
+ attrs, /*com.android.internal.R.styleable.*/R_styleable_LinearLayout, defStyle, defStyle);
+
+ try {
+ final Drawable d = a.getDrawable(/*com.android.internal.R.styleable.*/LinearLayout_divider);
+ if (d != null) {
+ // If a divider is specified use its intrinsic height for divider height
+ setDividerDrawable(d);
+ }
+
+ } finally {
+ a.recycle();
+ }
+
+ a = getContext().getTheme().obtainStyledAttributes(
+ attrs, R.styleable.card_listItem, defStyle, defStyle);
+ try {
+ // Use the height specified, zero being the default
+ final int dividerHeight = a.getDimensionPixelSize(
+ R.styleable.card_listItem_card_list_item_dividerHeight, 0);
+ if (dividerHeight != 0) {
+ setDividerHeight(dividerHeight);
+ }
+ } finally {
+ a.recycle();
+ }
+ }
+
+ // -------------------------------------------------------------
+ // Divider
+ // -------------------------------------------------------------
+
+ private static final int[] R_styleable_LinearLayout = new int[]{
+ /* 0 */ android.R.attr.divider,
+ /* 1 */ android.R.attr.measureWithLargestChild,
+ /* 2 */ android.R.attr.showDividers,
+ /* 3 */ android.R.attr.dividerPadding,
+ };
+ private static final int LinearLayout_divider = 0;
+
+ private Drawable mDivider;
+ protected int mDividerWidth;
+ protected int mDividerHeight;
+
+ /**
+ * Set a drawable to be used as a divider between items.
+ *
+ * @param divider Drawable that will divide each item.
+ * @see #setShowDividers(int)
+ */
+ public void setDividerDrawable(Drawable divider) {
+ if (divider == mDivider) {
+ return;
+ }
+ mDivider = divider;
+
+ if (divider != null) {
+ mDividerWidth = divider.getIntrinsicWidth();
+ mDividerHeight = divider.getIntrinsicHeight();
+ } else {
+ mDividerWidth = 0;
+ mDividerHeight = 0;
+ }
+ setWillNotDraw(divider == null);
+ requestLayout();
+ }
+
+
+ @Override
+ protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) {
+ final int index = indexOfChild(child);
+ final int orientation = getOrientation();
+ final LayoutParams params = (LayoutParams) child.getLayoutParams();
+ if (hasDividerBeforeChildAt(index)) {
+ if (orientation == VERTICAL) {
+ //Account for the divider by pushing everything up
+ params.topMargin = mDividerHeight;
+ } else {
+ //Account for the divider by pushing everything left
+ params.leftMargin = mDividerWidth;
+ }
+ }
+
+ final int count = getChildCount();
+ if (index == count - 1) {
+ if (hasDividerBeforeChildAt(count)) {
+ if (orientation == VERTICAL) {
+ params.bottomMargin = mDividerHeight;
+ } else {
+ params.rightMargin = mDividerWidth;
+ }
+ }
+ }
+ super.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ if (mDivider != null) {
+ if (getOrientation() == VERTICAL) {
+ drawDividersVertical(canvas);
+ } else {
+ drawDividersHorizontal(canvas);
+ }
+ }
+ super.onDraw(canvas);
+ }
+
+ void drawDividersVertical(Canvas canvas) {
+ final int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+
+ if (child != null && child.getVisibility() != GONE) {
+ if (hasDividerBeforeChildAt(i)) {
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ final int top = child.getTop() - lp.topMargin/* - mDividerHeight*/;
+ drawHorizontalDivider(canvas, top);
+ }
+ }
+ }
+
+ if (hasDividerBeforeChildAt(count)) {
+ final View child = getChildAt(count - 1);
+ int bottom = 0;
+ if (child == null) {
+ bottom = getHeight() - getPaddingBottom() - mDividerHeight;
+ } else {
+ //final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ bottom = child.getBottom()/* + lp.bottomMargin*/;
+ }
+ drawHorizontalDivider(canvas, bottom);
+ }
+ }
+
+ void drawDividersHorizontal(Canvas canvas) {
+ final int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+
+ if (child != null && child.getVisibility() != GONE) {
+ if (hasDividerBeforeChildAt(i)) {
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ final int left = child.getLeft() - lp.leftMargin/* - mDividerWidth*/;
+ drawVerticalDivider(canvas, left);
+ }
+ }
+ }
+
+ if (hasDividerBeforeChildAt(count)) {
+ final View child = getChildAt(count - 1);
+ int right = 0;
+ if (child == null) {
+ right = getWidth() - getPaddingRight() - mDividerWidth;
+ } else {
+ //final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ right = child.getRight()/* + lp.rightMargin*/;
+ }
+ drawVerticalDivider(canvas, right);
+ }
+ }
+
+ void drawHorizontalDivider(Canvas canvas, int top) {
+ mDivider.setBounds(getPaddingLeft() + getDividerPadding(), top,
+ getWidth() - getPaddingRight() - getDividerPadding(), top + mDividerHeight);
+ mDivider.draw(canvas);
+
+ }
+
+ void drawVerticalDivider(Canvas canvas, int left) {
+ mDivider.setBounds(left, getPaddingTop() + getDividerPadding(),
+ left + mDividerWidth, getHeight() - getPaddingBottom() - getDividerPadding());
+ mDivider.draw(canvas);
+ }
+
+ /**
+ * Determines where to position dividers between children.
+ *
+ * @param childIndex Index of child to check for preceding divider
+ * @return true if there should be a divider before the child at childIndex
+ * @hide Pending API consideration. Currently only used internally by the system.
+ */
+ protected boolean hasDividerBeforeChildAt(int childIndex) {
+ if (childIndex == 0) {
+ return (getShowDividers() & SHOW_DIVIDER_BEGINNING) != 0;
+ } else if (childIndex == getChildCount()) {
+ return (getShowDividers() & SHOW_DIVIDER_END) != 0;
+ } else if ((getShowDividers() & SHOW_DIVIDER_MIDDLE) != 0) {
+ boolean hasVisibleViewBefore = false;
+ for (int i = childIndex - 1; i >= 0; i--) {
+ if (getChildAt(i).getVisibility() != GONE) {
+ hasVisibleViewBefore = true;
+ break;
+ }
+ }
+ return hasVisibleViewBefore;
+ }
+ return false;
+ }
+
+ /**
+ * @return Returns the height of the divider that will be drawn between each item in the list.
+ */
+ public int getDividerHeight() {
+ return mDividerHeight;
+ }
+
+ /**
+ * Sets the height of the divider that will be drawn between each item in the list. Calling
+ * this will override the intrinsic height as set by {@link #setDividerDrawable(Drawable)}
+ *
+ * @param height The new height of the divider in pixels.
+ */
+ public void setDividerHeight(int height) {
+ if (getOrientation() == VERTICAL) {
+ mDividerHeight = height;
+ } else {
+ mDividerWidth = height;
+ }
+
+ requestLayout();
+ }
+
+ @Override
+ public void setOrientation(int orientation) {
+ if (orientation != getOrientation()) {
+ int tmp = mDividerHeight;
+ mDividerHeight = mDividerWidth;
+ mDividerWidth = tmp;
+ }
+ super.setOrientation(orientation);
+ }
+
+ // -------------------------------------------------------------
+ // Adapter
+ // -------------------------------------------------------------
+
+ /**
+ * Sets the adapter.
+ * Sets the data behind this LinearListView.
+ *
+ * @param listAdapter The ListAdapter which is responsible for maintaining the data
+ * backing this list and for producing a view to represent an
+ * item in that data set.
+ */
+ public void setAdapter(CardWithList.LinearListAdapter listAdapter) {
+ this.mListAdapter = listAdapter;
+ setOrientation(VERTICAL);
+
+ //Populate the list
+ if (mListAdapter != null) {
+ for (int i = 0; i < mListAdapter.getCount(); i++) {
+ View itemView = mListAdapter.getView(i, null, null);
+ if (itemView != null)
+ this.addView(itemView);
+ }
+ }
+ }
+
+ /**
+ * Returns the adapter
+ *
+ * @return
+ */
+ public CardWithList.LinearListAdapter getAdapter() {
+ return mListAdapter;
+ }
+
+
+ /**
+ * Get the position within the adapter's data set for the view, where view is a an adapter item
+ * or a descendant of an adapter item.
+ *
+ * @param view an adapter item, or a descendant of an adapter item. This must be visible in this
+ * AdapterView at the time of the call.
+ * @return the position within the adapter's data set of the view, or {@link #INVALID_POSITION}
+ * if the view does not correspond to a list item (or it is not currently visible).
+ */
+ public int getPositionForView(View view) {
+ View listItem = view;
+ try {
+ View v;
+ while (!(v = (View) listItem.getParent()).equals(this)) {
+ listItem = v;
+ }
+ } catch (ClassCastException e) {
+ // We made it up to the window without find this list itemView
+ return INVALID_POSITION;
+ }
+
+ // Search the children for the list item
+ final int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ if (getChildAt(i).equals(listItem)) {
+ return i;
+ }
+ }
+
+ // Child not found!
+ return INVALID_POSITION;
+ }
+} \ No newline at end of file
diff --git a/src/it/gmariotti/cardslib/library/prototypes/SectionedCardAdapter.java b/src/it/gmariotti/cardslib/library/prototypes/SectionedCardAdapter.java
new file mode 100644
index 0000000..0bf5df5
--- /dev/null
+++ b/src/it/gmariotti/cardslib/library/prototypes/SectionedCardAdapter.java
@@ -0,0 +1,346 @@
+/*
+ * ******************************************************************************
+ * Copyright (c) 2013-2014 Gabriele Mariotti.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * *****************************************************************************
+ */
+
+package com.android.cards.prototypes;
+
+import android.content.Context;
+import android.database.DataSetObserver;
+import android.util.SparseArray;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.util.Arrays;
+import java.util.Comparator;
+
+import com.android.cards.R;
+import com.android.cards.internal.CardArrayAdapter;
+
+/**
+ * An adapter to build a CardList with sections.
+ *
+ * @author Gabriele Mariotti (gabri.mariotti@gmail.com)
+ */
+public class SectionedCardAdapter extends BaseAdapter {
+
+ private boolean mValid = true;
+
+ /**
+ * Default layout used for sections
+ */
+ private int mSectionResourceId = R.layout.base_section_layout;
+
+ /**
+ * Inflater
+ */
+ private LayoutInflater mLayoutInflater;
+
+ /**
+ * Adapter with cards.
+ */
+ private BaseAdapter mBaseAdapter;
+
+ /**
+ * Array with Card Sections
+ */
+ private SparseArray<CardSection> mCardSections = new SparseArray<CardSection>();
+
+ // -------------------------------------------------------------
+ // Constructors
+ // -------------------------------------------------------------
+
+ /**
+ * Constructor
+ *
+ * @param context
+ * @param cardArrayAdapter
+ */
+ public SectionedCardAdapter(Context context, CardArrayAdapter cardArrayAdapter) {
+ this(context,R.layout.base_section_layout,cardArrayAdapter);
+ }
+
+ /**
+ *
+ * @param context context
+ * @param sectionResourceId layout used by sections
+ * @param cardArrayAdapter cardArrayAdapter
+ */
+ public SectionedCardAdapter(Context context, int sectionResourceId, CardArrayAdapter cardArrayAdapter) {
+ mLayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ mBaseAdapter = cardArrayAdapter;
+ mSectionResourceId = sectionResourceId;
+
+ mBaseAdapter.registerDataSetObserver(new DataSetObserver() {
+ @Override
+ public void onChanged() {
+ mValid = !mBaseAdapter.isEmpty();
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public void onInvalidated() {
+ mValid = false;
+ notifyDataSetInvalidated();
+ }
+ });
+ }
+
+ // -------------------------------------------------------------
+ // Section
+ // -------------------------------------------------------------
+
+ /**
+ * Sets the Card sections
+ *
+ * @param cardSections
+ */
+ public void setCardSections(CardSection[] cardSections) {
+ mCardSections.clear();
+
+ Arrays.sort(cardSections, new Comparator<CardSection>() {
+ @Override
+ public int compare(CardSection o, CardSection o1) {
+ return (o.firstPosition == o1.firstPosition)
+ ? 0
+ : ((o.firstPosition < o1.firstPosition) ? -1 : 1);
+ }
+ });
+
+ int offset = 0; // offset positions for the headers we're adding
+ for (CardSection cardSection : cardSections) {
+ cardSection.sectionedPosition = cardSection.firstPosition + offset;
+ mCardSections.append(cardSection.sectionedPosition, cardSection);
+ ++offset;
+ }
+
+ notifyDataSetChanged();
+ }
+
+ // -------------------------------------------------------------
+ // Adapter's methods
+ // -------------------------------------------------------------
+
+ /**
+ * Returns the sectioned position from the position
+ *
+ * @param position
+ * @return
+ */
+ public int positionToSectionedPosition(int position) {
+ int offset = 0;
+ for (int i = 0; i < mCardSections.size(); i++) {
+ if (mCardSections.valueAt(i).firstPosition > position) {
+ break;
+ }
+ ++offset;
+ }
+ return position + offset;
+ }
+
+ /**
+ * Returns the position from the sectioned position
+ * @param sectionedPosition
+ * @return
+ */
+ public int sectionedPositionToPosition(int sectionedPosition) {
+ if (isSectionHeaderPosition(sectionedPosition)) {
+ return ListView.INVALID_POSITION;
+ }
+
+ int offset = 0;
+ for (int i = 0; i < mCardSections.size(); i++) {
+ if (mCardSections.valueAt(i).sectionedPosition > sectionedPosition) {
+ break;
+ }
+ --offset;
+ }
+ return sectionedPosition + offset;
+ }
+
+ /**
+ * Returns true if the position is a Section
+ *
+ * @param position
+ * @return
+ */
+ public boolean isSectionHeaderPosition(int position) {
+ return mCardSections.get(position) != null;
+ }
+
+ @Override
+ public int getCount() {
+ return (mValid ? mBaseAdapter.getCount() + mCardSections.size() : 0);
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return isSectionHeaderPosition(position)
+ ? mCardSections.get(position)
+ : mBaseAdapter.getItem(sectionedPositionToPosition(position));
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return isSectionHeaderPosition(position)
+ ? Integer.MAX_VALUE - mCardSections.indexOfKey(position)
+ : mBaseAdapter.getItemId(sectionedPositionToPosition(position));
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ return isSectionHeaderPosition(position)
+ ? getViewTypeCount() - 1
+ : mBaseAdapter.getItemViewType(sectionedPositionToPosition(position));
+ }
+
+ @Override
+ public boolean isEnabled(int position) {
+ //noinspection SimplifiableConditionalExpression
+ return isSectionHeaderPosition(position)
+ ? false
+ : mBaseAdapter.isEnabled(sectionedPositionToPosition(position));
+ }
+
+ @Override
+ public int getViewTypeCount() {
+ return mBaseAdapter.getViewTypeCount() + 1; // the section headings
+ }
+
+ @Override
+ public boolean areAllItemsEnabled() {
+ return false;
+ }
+
+ @Override
+ public boolean hasStableIds() {
+ return mBaseAdapter.hasStableIds();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return mBaseAdapter.isEmpty();
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (isSectionHeaderPosition(position)) {
+ return internalSectionView(position, convertView, parent);
+ } else {
+ return mBaseAdapter.getView(sectionedPositionToPosition(position), convertView, parent);
+ }
+ }
+
+ /**
+ * Returns the view used by the section at position
+ *
+ * @param position section's position
+ * @param convertView
+ * @param parent
+ * @return
+ */
+ protected View internalSectionView(int position, View convertView, ViewGroup parent) {
+ View view = convertView;
+ if (view == null) {
+ view = mLayoutInflater.inflate(mSectionResourceId, parent, false);
+ }
+ getSectionView(position,view,parent);
+ return view;
+ }
+
+ /**
+ * Returns the view used by the section at position.
+ * Override this method to set your ui elements.
+ *
+ * @param position section's position
+ * @param view
+ * @param parent
+ * @return
+ */
+ protected View getSectionView(int position, View view, ViewGroup parent) {
+
+ TextView textView = (TextView) view.findViewById(R.id.card_section_simple_title);
+ if (textView != null)
+ textView.setText(mCardSections.get(position).title);
+
+ return view;
+ }
+
+ /**
+ * Use this method to add a single {@link CardSection}.</p>
+ * If you want to add more CardSections use the method {@link #addCardSections(CardSection[])}
+ *
+ * @param cardSection to be added
+ */
+ public void addCardSection(CardSection cardSection) {
+
+ if (cardSection != null) {
+ int oldSize = mCardSections.size();
+ CardSection[] newCardSections = new CardSection[oldSize + 1];
+
+ //Get current sections
+ for (int i = 0; i < mCardSections.size(); i++) {
+ newCardSections[i] = mCardSections.valueAt(i);
+ }
+ //Add new section
+ newCardSections[oldSize] = cardSection;
+ setCardSections(newCardSections);
+ }
+ }
+
+ /**
+ * Adds card Sections
+ *
+ * @param cardSections card sections to be added
+ */
+ public void addCardSections(CardSection[] cardSections) {
+
+ if (cardSections != null && cardSections.length>0) {
+
+ int oldSize = mCardSections.size();
+
+ //Get current sections
+ CardSection[] newCardSections = new CardSection[oldSize + cardSections.length];
+ for (int i = 0; i < mCardSections.size(); i++) {
+ newCardSections[i] = mCardSections.valueAt(i);
+ }
+
+ //Add new sections
+ for (int i = 0; i < cardSections.length; i++){
+ newCardSections[i + oldSize] = cardSections[i];
+ }
+
+ setCardSections(newCardSections);
+ }
+ }
+
+ // -------------------------------------------------------------
+ // Getters and setters
+ // -------------------------------------------------------------
+
+ /**
+ * Returns the sections
+ * @return
+ */
+ public SparseArray<CardSection> getCardSections() {
+ return mCardSections;
+ }
+
+}
diff --git a/src/it/gmariotti/cardslib/library/prototypes/SwipeDismissListItemViewTouchListener.java b/src/it/gmariotti/cardslib/library/prototypes/SwipeDismissListItemViewTouchListener.java
new file mode 100644
index 0000000..1c28f1a
--- /dev/null
+++ b/src/it/gmariotti/cardslib/library/prototypes/SwipeDismissListItemViewTouchListener.java
@@ -0,0 +1,289 @@
+/*
+ * ******************************************************************************
+ * Copyright (c) 2013-2014 Gabriele Mariotti.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * *****************************************************************************
+ */
+
+package com.android.cards.prototypes;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.graphics.Rect;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.widget.ListView;
+
+import com.android.cards.R;
+import com.android.cards.internal.Card;
+
+/**
+ * @author Gabriele Mariotti (gabri.mariotti@gmail.com)
+ */
+public class SwipeDismissListItemViewTouchListener implements View.OnTouchListener {
+
+
+ /**
+ * The callback interface used by {@link SwipeDismissListItemViewTouchListener} to inform its client
+ * about a successful dismissal of one or more list item positions.
+ */
+ public interface DismissCallbacks {
+
+ /**
+ * Called to determine whether the given position can be dismissed.
+ */
+ boolean canDismiss(int position, Card card, CardWithList.ListObject listObject);
+
+ /**
+ * Called when the user has indicated they she would like to dismiss one or more list item
+ * positions.
+ *
+ * @param listView The originating {@link ListView}.
+ * @param position position to dismiss
+ */
+ void onDismiss(LinearListView listView, int position,boolean dismissRight);
+ }
+
+
+ private CardWithList.ListObject mListObject;
+ private LinearListView mListView;
+
+ // Cached ViewConfiguration and system-wide constant values
+ private int mSlop;
+ private int mMinFlingVelocity;
+ private int mMaxFlingVelocity;
+ private long mAnimationTime;
+
+ // Fixed properties
+ private View itemView;
+ private DismissCallbacks mCallbacks;
+ private int mViewWidth = 1; // 1 and not 0 to prevent dividing by zero
+
+ // Transient properties
+ private float mDownX;
+ private float mDownY;
+ //private Card mToken;
+ private boolean mSwiping;
+ private VelocityTracker mVelocityTracker;
+ private boolean mPaused;
+ private float mTranslationX;
+ private int mSwipingSlop;
+ private int mDownPosition;
+ private View mDownView;
+
+ private int swipeDistanceDivisor = 2;
+
+ public SwipeDismissListItemViewTouchListener(LinearListView listView, DismissCallbacks callbacks) {
+ ViewConfiguration vc = ViewConfiguration.get(listView.getContext());
+ mSlop = vc.getScaledTouchSlop();
+ mMinFlingVelocity = vc.getScaledMinimumFlingVelocity() * 16;
+ mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity();
+ mAnimationTime = listView.getContext().getResources().getInteger(
+ android.R.integer.config_shortAnimTime);
+
+ this.mListView = listView;
+ mCallbacks = callbacks;
+ swipeDistanceDivisor = listView.getContext().getResources().getInteger(R.integer.list_card_swipe_distance_divisor);
+ }
+
+
+ @Override
+ public boolean onTouch(View view, MotionEvent motionEvent) {
+
+ if (mViewWidth < 2) {
+ mViewWidth = mListView.getWidth();
+ }
+
+ switch (motionEvent.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN: {
+
+ if (mPaused) {
+ return false;
+ }
+
+ if (mSwiping) {
+ return true;
+ }
+
+ // Find the child view that was touched (perform a hit test)
+ Rect rect = new Rect();
+ int childCount = mListView.getChildCount();
+ int headerCount = 0;
+ int footerCount = 0;
+ int[] listViewCoords = new int[2];
+ mListView.getLocationOnScreen(listViewCoords);
+ int x = (int) motionEvent.getRawX() - listViewCoords[0];
+ int y = (int) motionEvent.getRawY() - listViewCoords[1];
+ View child=null;
+ for (int i = headerCount; i < (childCount - footerCount); i++) {
+ child = mListView.getChildAt(i);
+ child.getHitRect(rect);
+ if (rect.contains(x, y)) {
+ mDownView = child;
+ break;
+ }
+ }
+
+ if (mDownView != null) {
+ mDownX = motionEvent.getRawX();
+ mDownY = motionEvent.getRawY();
+ mDownPosition = mListView.getPositionForView(mDownView);
+ CardWithList.ListObject object = mListView.getAdapter().getItem(mDownPosition);
+ if (mCallbacks.canDismiss(mDownPosition, object.getParentCard(), object)) {
+ mVelocityTracker = VelocityTracker.obtain();
+ mVelocityTracker.addMovement(motionEvent);
+ } else {
+ mDownView = null;
+ }
+ }
+ view.onTouchEvent(motionEvent);
+ return false;
+
+ }
+ case MotionEvent.ACTION_MOVE: {
+ if (mVelocityTracker == null || mPaused) {
+ break;
+ }
+
+ mVelocityTracker.addMovement(motionEvent);
+ float deltaX = motionEvent.getRawX() - mDownX;
+ float deltaY = motionEvent.getRawY() - mDownY;
+ if (Math.abs(deltaX) > mSlop && Math.abs(deltaY) < Math.abs(deltaX) / 2) {
+ mSwiping = true;
+ mSwipingSlop = (deltaX > 0 ? mSlop : -mSlop);
+ mDownView.getParent().requestDisallowInterceptTouchEvent(true);
+ mListView.requestDisallowInterceptTouchEvent(true);
+
+ // Cancel ListView's touch (un-highlighting the item)
+ MotionEvent cancelEvent = MotionEvent.obtain(motionEvent);
+ cancelEvent
+ .setAction(MotionEvent.ACTION_CANCEL
+ | (motionEvent.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT));
+ mDownView.onTouchEvent(cancelEvent);
+ cancelEvent.recycle();
+ }
+
+ if (mSwiping) {
+ mDownView.setTranslationX(deltaX - mSwipingSlop);
+
+ /* mDownView.setAlpha(Math.max(0f, Math.min(1f,
+ 1f - 2f * Math.abs(deltaX) / mViewWidth)));
+ */
+ return true;
+ }
+ break;
+ }
+
+ case MotionEvent.ACTION_UP: {
+ if (mVelocityTracker == null) {
+ break;
+ }
+
+ float deltaX = motionEvent.getRawX() - mDownX;
+ mVelocityTracker.addMovement(motionEvent);
+ mVelocityTracker.computeCurrentVelocity(1000);
+ float velocityX = mVelocityTracker.getXVelocity();
+ float absVelocityX = Math.abs(velocityX);
+ float absVelocityY = Math.abs(mVelocityTracker.getYVelocity());
+ boolean dismiss = false;
+ boolean dismissRight = false;
+ if (Math.abs(deltaX) > mViewWidth / swipeDistanceDivisor) {
+ dismiss = true;
+ dismissRight = deltaX > 0;
+ } else if (mMinFlingVelocity <= absVelocityX && absVelocityX <= mMaxFlingVelocity
+ && absVelocityY < absVelocityX && mSwiping) {
+ // dismiss only if flinging in the same direction as dragging
+ dismiss = (velocityX < 0) == (deltaX < 0);
+ dismissRight = mVelocityTracker.getXVelocity() > 0;
+ }
+ if (dismiss && mDownPosition != ListView.INVALID_POSITION) {
+
+ // dismiss
+ dismiss(mDownView, mDownPosition, dismissRight);
+
+ } else {
+ // cancel
+ mDownView.animate().translationX(0).alpha(1)
+ .setDuration(mAnimationTime).setListener(null);
+ }
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ mDownX = 0;
+ mDownY = 0;
+ mDownView = null;
+ mDownPosition = ListView.INVALID_POSITION;
+ if (mSwiping){
+ //To prevent onClick event with a fast swipe
+ mSwiping = false;
+ return true;
+ }
+ mSwiping = false;
+ break;
+ }
+
+ case MotionEvent.ACTION_CANCEL: {
+ if (mVelocityTracker == null) {
+ break;
+ }
+
+ if (mDownView != null) {
+ // cancel
+ mDownView.animate()
+ .translationX(0)
+ .alpha(1)
+ .setDuration(mAnimationTime)
+ .setListener(null);
+ }
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ mDownX = 0;
+ mDownY = 0;
+ mDownView = null;
+ mDownPosition = ListView.INVALID_POSITION;
+ mSwiping = false;
+ break;
+ }
+
+ }
+
+ return false;
+ }
+
+ private void dismiss(final View view, final int position, final boolean dismissRight) {
+ if (view == null) {
+ // No view, shortcut to calling onDismiss to let it deal with adapter
+ // updates and all that.
+ mCallbacks.onDismiss(mListView, position, dismissRight );
+ return;
+ }
+
+ view.animate()
+ .translationX(dismissRight ? mViewWidth : -mViewWidth)
+ .alpha(0)
+ .setDuration(mAnimationTime)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ finalizeDismiss(view, position,dismissRight);
+ }
+ });
+ }
+
+ private void finalizeDismiss(final View dismissView, final int dismissPosition,final boolean dismissRight ) {
+ mCallbacks.onDismiss(mListView, dismissPosition,dismissRight);
+ }
+
+}
diff --git a/src/com/android/cards/utils/BitmapUtils.java b/src/it/gmariotti/cardslib/library/utils/BitmapUtils.java
index 0e1b0df..0e1b0df 100644
--- a/src/com/android/cards/utils/BitmapUtils.java
+++ b/src/it/gmariotti/cardslib/library/utils/BitmapUtils.java
diff --git a/src/com/android/cards/utils/CacheUtil.java b/src/it/gmariotti/cardslib/library/utils/CacheUtil.java
index 27e1044..27e1044 100644
--- a/src/com/android/cards/utils/CacheUtil.java
+++ b/src/it/gmariotti/cardslib/library/utils/CacheUtil.java
diff --git a/src/com/android/cards/view/BaseCardView.java b/src/it/gmariotti/cardslib/library/view/BaseCardView.java
index ec601e3..af1e66c 100644
--- a/src/com/android/cards/view/BaseCardView.java
+++ b/src/it/gmariotti/cardslib/library/view/BaseCardView.java
@@ -32,6 +32,8 @@ import com.android.cards.view.base.CardViewInterface;
import com.android.cards.view.component.CardHeaderView;
import com.android.cards.view.component.CardShadowView;
import com.android.cards.view.component.CardThumbnailView;
+import com.android.cards.view.helper.CardViewHelper;
+import com.android.cards.view.helper.CardViewHelperUtil;
/**
* BaseView for Card
@@ -87,23 +89,25 @@ public class BaseCardView extends LinearLayout implements CardViewInterface {
*/
protected boolean mForceReplaceInnerLayout =false;
+ protected CardViewHelper mHelperImpl;
+
//--------------------------------------------------------------------------
// Constructor
//--------------------------------------------------------------------------
public BaseCardView(Context context) {
- super(context);
- init(null, 0);
+ this(context, null, 0);
}
public BaseCardView(Context context, AttributeSet attrs) {
- super(context, attrs);
- init(attrs, 0);
+ this(context, attrs, 0);
}
public BaseCardView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs, defStyle);
+
+ mHelperImpl = CardViewHelperUtil.getInstance(context);
}
//--------------------------------------------------------------------------
diff --git a/src/it/gmariotti/cardslib/library/view/CardExpandableListView.java b/src/it/gmariotti/cardslib/library/view/CardExpandableListView.java
new file mode 100644
index 0000000..e33aab2
--- /dev/null
+++ b/src/it/gmariotti/cardslib/library/view/CardExpandableListView.java
@@ -0,0 +1,149 @@
+/*
+ * ******************************************************************************
+ * Copyright (c) 2013-2014 Gabriele Mariotti.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * *****************************************************************************
+ */
+
+package com.android.cards.view;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.widget.ExpandableListView;
+import android.widget.ListAdapter;
+
+import com.android.cards.R;
+import com.android.cards.internal.CardExpandableListAdapter;
+
+/**
+ * @author Gabriele Mariotti (gabri.mariotti@gmail.com)
+ */
+public class CardExpandableListView extends ExpandableListView{
+
+ protected static String TAG = "CardExpandableListView";
+
+ /**
+ * CardExpandableListAdapter
+ */
+ protected CardExpandableListAdapter mAdapter;
+
+ //--------------------------------------------------------------------------
+ // Custom Attrs
+ //--------------------------------------------------------------------------
+
+ /**
+ * Default layout to apply to card
+ */
+ protected int list_card_layout_resourceID = R.layout.list_card_layout;
+
+ //--------------------------------------------------------------------------
+ // Constructors
+ //--------------------------------------------------------------------------
+
+ public CardExpandableListView(Context context) {
+ super(context);
+ init(null, 0);
+ }
+
+ public CardExpandableListView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(attrs, 0);
+ }
+
+ public CardExpandableListView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init(attrs, defStyle);
+ }
+
+ //--------------------------------------------------------------------------
+ // Init
+ //--------------------------------------------------------------------------
+
+ /**
+ * Initialize
+ *
+ * @param attrs
+ * @param defStyle
+ */
+ protected void init(AttributeSet attrs, int defStyle){
+
+ //Init attrs
+ initAttrs(attrs,defStyle);
+
+ //Set divider to 0dp
+ setDividerHeight(0);
+
+ }
+
+
+ /**
+ * Init custom attrs.
+ *
+ * @param attrs
+ * @param defStyle
+ */
+ protected void initAttrs(AttributeSet attrs, int defStyle) {
+
+ list_card_layout_resourceID = R.layout.list_card_layout;
+
+ TypedArray a = getContext().getTheme().obtainStyledAttributes(
+ attrs, R.styleable.card_options, defStyle, defStyle);
+
+ try {
+ list_card_layout_resourceID = a.getResourceId(R.styleable.card_options_list_card_layout_resourceID, this.list_card_layout_resourceID);
+ } finally {
+ a.recycle();
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ // Adapter
+ //--------------------------------------------------------------------------
+
+ /**
+ * Set the adapter. You can provide a {@link com.android.cards.internal.CardArrayAdapter}, or a {@link com.android.cards.internal.CardCursorAdapter}
+ * or a generic adapter.
+ * Pay attention: your generic adapter has to call {@link com.android.cards.internal.CardArrayAdapter#getView} method
+ *
+ * @param adapter
+ */
+ @Override
+ public void setAdapter(ListAdapter adapter) {
+ if (adapter instanceof CardExpandableListAdapter){
+ setAdapter(adapter);
+ }else {
+ Log.w(TAG, "You are using a generic adapter. Pay attention: your adapter has to call cardArrayAdapter#getView method");
+ super.setAdapter(adapter);
+ }
+ }
+
+ /**
+ * Set {@link CardExpandableListAdapter} and layout used by items in ListView
+ *
+ * @param adapter {@link CardExpandableListAdapter}
+ */
+ public void setAdapter(CardExpandableListAdapter adapter) {
+ super.setAdapter(adapter);
+
+ //Set Layout used by items
+ adapter.setGroupLayoutId(list_card_layout_resourceID);
+
+ adapter.setCardListView(this);
+ mAdapter=adapter;
+ }
+
+
+}
diff --git a/src/com/android/cards/view/CardGridView.java b/src/it/gmariotti/cardslib/library/view/CardGridView.java
index 3b44261..9b49fb7 100644
--- a/src/com/android/cards/view/CardGridView.java
+++ b/src/it/gmariotti/cardslib/library/view/CardGridView.java
@@ -29,6 +29,7 @@ import android.widget.ListAdapter;
import com.android.cards.R;
import com.android.cards.internal.CardGridArrayAdapter;
import com.android.cards.internal.CardGridCursorAdapter;
+import com.android.cards.view.base.CardViewWrapper;
/**
* Card Grid View.
@@ -61,7 +62,7 @@ import com.android.cards.internal.CardGridCursorAdapter;
* </p>
* @author Gabriele Mariotti (gabri.mariotti@gmail.com)
*/
-public class CardGridView extends GridView implements CardView.OnExpandListAnimatorListener {
+public class CardGridView extends GridView implements CardViewWrapper.OnExpandListAnimatorListener {
protected static String TAG = "CardGridView";
@@ -232,13 +233,13 @@ public class CardGridView extends GridView implements CardView.OnExpandListAnima
//--------------------------------------------------------------------------
@Override
- public void onExpandStart(CardView viewCard,View expandingLayout) {
+ public void onExpandStart(CardViewWrapper viewCard,View expandingLayout) {
//do nothing. Don't use this kind of animation in a grid
Log.w(TAG,"Don't use this kind of animation in a grid");
}
@Override
- public void onCollapseStart(CardView viewCard,View expandingLayout) {
+ public void onCollapseStart(CardViewWrapper viewCard,View expandingLayout) {
//do nothing. Don't use this kind of animation in a grid
Log.w(TAG,"Don't use this kind of animation in a grid");
}
diff --git a/src/com/android/cards/view/CardListView.java b/src/it/gmariotti/cardslib/library/view/CardListView.java
index e61ffcc..784b5cf 100644
--- a/src/com/android/cards/view/CardListView.java
+++ b/src/it/gmariotti/cardslib/library/view/CardListView.java
@@ -25,7 +25,6 @@ import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.Log;
-import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
@@ -36,6 +35,7 @@ import com.android.cards.R;
import com.android.cards.internal.Card;
import com.android.cards.internal.CardArrayAdapter;
import com.android.cards.internal.CardCursorAdapter;
+import com.android.cards.view.base.CardViewWrapper;
import com.android.cards.view.listener.SwipeOnScrollListener;
/**
@@ -63,7 +63,7 @@ import com.android.cards.view.listener.SwipeOnScrollListener;
* </p>
* @author Gabriele Mariotti (gabri.mariotti@gmail.com)
*/
-public class CardListView extends ListView implements CardView.OnExpandListAnimatorListener {
+public class CardListView extends ListView implements CardViewWrapper.OnExpandListAnimatorListener {
protected static String TAG = "CardListView";
@@ -82,11 +82,6 @@ public class CardListView extends ListView implements CardView.OnExpandListAnima
*/
protected SwipeOnScrollListener mOnScrollListener;
- /**
- * Custom gesture listener to be used with a CardListView and cards with swipe action
- */
- protected ScaleGestureDetector mGestureDetector;
-
//--------------------------------------------------------------------------
// Custom Attrs
@@ -260,26 +255,12 @@ public class CardListView extends ListView implements CardView.OnExpandListAnima
this.mOnScrollListener = (SwipeOnScrollListener)mOnScrollListener;
}
- /**
- * Set external custom gesture detector
- */
- public void setGestureDetector(ScaleGestureDetector gestureDetector) {
- this.mGestureDetector = gestureDetector;
- }
-
- /**
- * Get external custom gesture detector
- */
- public ScaleGestureDetector getGestureDetector() {
- return this.mGestureDetector;
- }
-
//--------------------------------------------------------------------------
// Expand and Collapse animator
//--------------------------------------------------------------------------
@Override
- public void onExpandStart(CardView viewCard,View expandingLayout) {
+ public void onExpandStart(CardViewWrapper viewCard,View expandingLayout) {
boolean expandable = true;
if (mCursorAdapter!=null){
@@ -296,7 +277,7 @@ public class CardListView extends ListView implements CardView.OnExpandListAnima
}
@Override
- public void onCollapseStart(CardView viewCard,View expandingLayout) {
+ public void onCollapseStart(CardViewWrapper viewCard,View expandingLayout) {
boolean collapsible = true;
if (mCursorAdapter!=null){
collapsible = mCursorAdapter.onCollapseStart(viewCard);
@@ -322,8 +303,7 @@ public class CardListView extends ListView implements CardView.OnExpandListAnima
* @param cardView cardView
* @param listView listView
*/
- public static void animateCollapsing(final View expandingLayout,
- final CardView cardView,final AbsListView listView) {
+ public static void animateCollapsing(final View expandingLayout, final CardViewWrapper cardView,final AbsListView listView) {
int origHeight = expandingLayout.getHeight();
ValueAnimator animator = createHeightAnimator(expandingLayout, origHeight, 0);
@@ -352,19 +332,16 @@ public class CardListView extends ListView implements CardView.OnExpandListAnima
* @param cardView cardView
* @param listView listView
*/
- public static void animateExpanding(final View expandingLayout,
- final CardView cardView,final AbsListView listView) {
+ public static void animateExpanding(final View expandingLayout, final CardViewWrapper cardView,final AbsListView listView) {
/* Update the layout so the extra content becomes visible.*/
expandingLayout.setVisibility(View.VISIBLE);
View parent = (View) expandingLayout.getParent();
- final int widthSpec = View.MeasureSpec.makeMeasureSpec(parent.getMeasuredWidth()
- - parent.getPaddingLeft() - parent.getPaddingRight(), View.MeasureSpec.AT_MOST);
+ final int widthSpec = View.MeasureSpec.makeMeasureSpec(parent.getMeasuredWidth() - parent.getPaddingLeft() - parent.getPaddingRight(), View.MeasureSpec.AT_MOST);
final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
expandingLayout.measure(widthSpec, heightSpec);
- ValueAnimator animator =
- createHeightAnimator(expandingLayout, 0, expandingLayout.getMeasuredHeight());
+ ValueAnimator animator = createHeightAnimator(expandingLayout, 0, expandingLayout.getMeasuredHeight());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
final int listViewHeight = listView.getHeight();
final int listViewBottomPadding = listView.getPaddingBottom();
@@ -376,8 +353,7 @@ public class CardListView extends ListView implements CardView.OnExpandListAnima
if (bottom > listViewHeight) {
final int top = v.getTop();
if (top > 0) {
- listView.smoothScrollBy(Math.min(
- bottom - listViewHeight + listViewBottomPadding, top), 0);
+ listView.smoothScrollBy(Math.min(bottom - listViewHeight + listViewBottomPadding, top), 0);
}
}
}
@@ -409,8 +385,7 @@ public class CardListView extends ListView implements CardView.OnExpandListAnima
return result;
}
- public static ValueAnimator createHeightAnimator(
- final View view, final int start, final int end) {
+ public static ValueAnimator createHeightAnimator(final View view, final int start, final int end) {
ValueAnimator animator = ValueAnimator.ofInt(start, end);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
diff --git a/src/com/android/cards/view/CardView.java b/src/it/gmariotti/cardslib/library/view/CardView.java
index a6f1353..6d748e9 100644
--- a/src/com/android/cards/view/CardView.java
+++ b/src/it/gmariotti/cardslib/library/view/CardView.java
@@ -22,6 +22,7 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
@@ -29,6 +30,7 @@ import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
@@ -41,6 +43,7 @@ import com.android.cards.internal.CardExpand;
import com.android.cards.internal.CardHeader;
import com.android.cards.internal.CardThumbnail;
import com.android.cards.internal.ViewToClickToExpand;
+import com.android.cards.view.base.CardViewWrapper;
import com.android.cards.view.component.CardHeaderView;
import com.android.cards.view.component.CardThumbnailView;
import com.android.cards.view.listener.SwipeDismissViewTouchListener;
@@ -98,7 +101,7 @@ import com.android.cards.view.listener.SwipeDismissViewTouchListener;
* </p>
* @author Gabriele Mariotti (gabri.mariotti@gmail.com)
*/
-public class CardView extends BaseCardView {
+public class CardView extends BaseCardView implements CardViewWrapper {
//--------------------------------------------------------------------------
//
@@ -201,6 +204,15 @@ public class CardView extends BaseCardView {
}
}
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ @Override
+ public void drawableHotspotChanged(float x, float y) {
+ super.drawableHotspotChanged(x, y);
+ if (mInternalMainCardLayout != null && mInternalMainCardLayout instanceof ForegroundLinearLayout) {
+ mInternalMainCardLayout.drawableHotspotChanged(x,y);
+ }
+ }
+
//--------------------------------------------------------------------------
// Card
//--------------------------------------------------------------------------
@@ -275,6 +287,9 @@ public class CardView extends BaseCardView {
//Setup Expand View
setupExpandView();
+ //Setup Supplemental Actions
+ setupSupplementalActions();
+
//Setup Listeners
setupListeners();
@@ -403,6 +418,11 @@ public class CardView extends BaseCardView {
}
}
+ protected void setupSupplementalActions() {
+ if (mCard != null)
+ mCard.setupSupplementalActions();
+ }
+
//--------------------------------------------------------------------------
// Listeners
//--------------------------------------------------------------------------
@@ -410,8 +430,8 @@ public class CardView extends BaseCardView {
protected void setupExpandAction(){
//Config ExpandLayout and its animation
- if ( (mInternalExpandLayout !=null && mCardHeader!=null && mCardHeader.isButtonExpandVisible() ) ||
- mCard.getViewToClickToExpand()!=null ){
+ if ( mInternalExpandLayout !=null && ( (mCardHeader!=null && mCardHeader.isButtonExpandVisible()) ||
+ mCard.getViewToClickToExpand()!=null) ){
//Create the expand/collapse animator
mInternalExpandLayout.getViewTreeObserver().addOnPreDrawListener(
@@ -420,22 +440,13 @@ public class CardView extends BaseCardView {
@Override
public boolean onPreDraw() {
mInternalExpandLayout.getViewTreeObserver().removeOnPreDrawListener(this);
- //mInternalExpandLayout.setVisibility(View.GONE);
View parent = (View) mInternalExpandLayout.getParent();
- final int widthSpec = View.MeasureSpec.makeMeasureSpec(
- parent.getMeasuredWidth() - parent.getPaddingLeft()
- - parent.getPaddingRight(), View.MeasureSpec.AT_MOST);
- final int heightSpec = View.MeasureSpec.makeMeasureSpec(
- LayoutParams.WRAP_CONTENT, View.MeasureSpec.AT_MOST);
-
+ final int widthSpec = View.MeasureSpec.makeMeasureSpec(parent.getMeasuredWidth() - parent.getPaddingLeft() - parent.getPaddingRight(), View.MeasureSpec.AT_MOST);
+ final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
mInternalExpandLayout.measure(widthSpec, heightSpec);
- final int widthSpecCard = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
- final int heightSpecCard = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
- mCollapsedHeight = getMeasuredHeight();
-
- mExpandAnimator = createSlideAnimator(0, mInternalExpandLayout.getMeasuredHeight());
+ mExpandAnimator = ExpandCollapseHelper.createSlideAnimator((CardView)mCard.getCardView(), 0, mInternalExpandLayout.getMeasuredHeight());
return true;
}
});
@@ -452,21 +463,43 @@ public class CardView extends BaseCardView {
@SuppressLint("NewApi")
protected void setupListeners(){
- // Swipe listener
- addGlobalSwipeListener(this);
+ //Swipe listener
+ if (mCard.isSwipeable()){
+ this.setOnTouchListener(new SwipeDismissViewTouchListener(this, mCard,new SwipeDismissViewTouchListener.DismissCallbacks() {
+ @Override
+ public boolean canDismiss(Card card) {
+ return card.isSwipeable();
+ }
- // OnClick listeners and partial listener
+ @Override
+ public void onDismiss(CardViewWrapper cardView, Card card) {
+ final ViewGroup vg = (ViewGroup)(((View)cardView).getParent());
+ if (vg!=null){
+ vg.removeView((View)cardView);
+ card.onSwipeCard();
+ }
+ }
+ }));
+ }else{
+ this.setOnTouchListener(null);
+ }
- // Reset Partial Listeners
- resetPartialListeners();
+ //OnClick listeners and partial listener
- boolean hasPartialClickListener = false;
+ //Reset Partial Listeners
+ resetPartialListeners();
if (mCard.isClickable()){
//Set the onClickListener
if(!mCard.isMultiChoiceEnabled()){
if (mCard.getOnClickListener() != null) {
- addGlobalClickListener(this);
+ this.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mCard.getOnClickListener()!=null)
+ mCard.getOnClickListener().onClick(mCard,v);
+ }
+ });
//Prevent multiple events
//if (!mCard.isSwipeable() && mCard.getOnSwipeListener() == null) {
@@ -476,7 +509,7 @@ public class CardView extends BaseCardView {
}else{
HashMap<Integer,Card.OnCardClickListener> mMultipleOnClickListner=mCard.getMultipleOnClickListener();
if (mMultipleOnClickListner!=null && !mMultipleOnClickListner.isEmpty()){
- hasPartialClickListener = true;
+
for (int key:mMultipleOnClickListner.keySet()){
View viewClickable= decodeAreaOnClickListener(key);
final Card.OnCardClickListener mListener=mMultipleOnClickListner.get(key);
@@ -493,11 +526,8 @@ public class CardView extends BaseCardView {
//Add Selector to this view
if (key > Card.CLICK_LISTENER_ALL_VIEW) {
- if (Build.VERSION.SDK_INT >= 16){
- viewClickable.setBackground(getResources().getDrawable(R.drawable.card_selector));
- } else {
- viewClickable.setBackgroundDrawable(getResources().getDrawable(R.drawable.card_selector));
- }
+ mHelperImpl.setCardSelector(viewClickable, getResources().getDrawable(R.drawable.card_selector));
+
}
}
}
@@ -511,87 +541,18 @@ public class CardView extends BaseCardView {
this.setClickable(false);
}
- // LongClick and partial listeners.
- if (mCard.isLongClickable()) {
- if (mCard.getOnLongClickListener() != null) {
- this.setOnLongClickListener(new OnLongClickListener() {
- @Override
- public boolean onLongClick(View v) {
- if (mCard.getOnLongClickListener()!=null)
- return mCard.getOnLongClickListener().onLongClick(mCard, v);
- return false;
- }
- });
- }
- HashMap<Integer, Card.OnLongCardClickListener> multipleOnLongClickListner =
- mCard.getMultipleOnLongClickListener();
- if (multipleOnLongClickListner != null && !multipleOnLongClickListner.isEmpty()) {
-
- for (int key : multipleOnLongClickListner.keySet()) {
- View viewLongClickable = decodeAreaOnClickListener(key);
- final Card.OnLongCardClickListener listener =
- multipleOnLongClickListner.get(key);
- if (viewLongClickable != null) {
- //Add listener to this view
- viewLongClickable.setOnLongClickListener(new OnLongClickListener() {
- @Override
- public boolean onLongClick(View v) {
- //Callback to card listener
- if (listener != null) {
- return listener.onLongClick(mCard, v);
- }
- return false;
- }
- });
- // We may have only partial longclicklistener. So add for each view
- // in this case the global click listener.
- // As well add for this view if available the swipe listener.
- addGlobalSwipeListener(viewLongClickable);
- if (!hasPartialClickListener) {
- addGlobalClickListener(viewLongClickable);
- }
- }
- }
- }
- } else {
- this.setLongClickable(false);
- }
- }
-
- private void addGlobalClickListener(View view) {
- if (mCard.isClickable() && !mCard.isMultiChoiceEnabled()
- && mCard.getOnClickListener() != null) {
- view.setOnClickListener(new OnClickListener() {
+ //LongClick listener
+ if(mCard.isLongClickable()){
+ this.setOnLongClickListener(new OnLongClickListener() {
@Override
- public void onClick(View v) {
- if (mCard.getOnClickListener() != null) {
- mCard.getOnClickListener().onClick(mCard, v);
- }
+ public boolean onLongClick(View v) {
+ if (mCard.getOnLongClickListener()!=null)
+ return mCard.getOnLongClickListener().onLongClick(mCard,v);
+ return false;
}
});
- }
- }
-
- private void addGlobalSwipeListener(View view) {
- if (mCard.isSwipeable()) {
- view.setOnTouchListener(new SwipeDismissViewTouchListener(this,
- mCard, new SwipeDismissViewTouchListener.DismissCallbacks() {
- @Override
- public boolean canDismiss(Card card) {
- return card.isSwipeable();
- }
-
- @Override
- public void onDismiss(CardView cardView, Card card) {
- final ViewGroup vg = (ViewGroup)(cardView.getParent());
- if (vg!=null){
- vg.removeView(cardView);
- card.onSwipeCard();
- }
- }
- }));
- } else {
- view.setOnTouchListener(null);
+ }else{
+ this.setLongClickable(false);
}
}
@@ -599,26 +560,17 @@ public class CardView extends BaseCardView {
* Reset all partial listeners
*/
protected void resetPartialListeners() {
- View viewClickable = decodeAreaOnClickListener(Card.CLICK_LISTENER_HEADER_VIEW);
- if (viewClickable != null) {
- viewClickable.setClickable(false);
- viewClickable.setLongClickable(false);
- }
- viewClickable = decodeAreaOnClickListener(Card.CLICK_LISTENER_THUMBNAIL_VIEW);
- if (viewClickable != null) {
+ View viewClickable= decodeAreaOnClickListener(Card.CLICK_LISTENER_HEADER_VIEW);
+ if (viewClickable!=null)
viewClickable.setClickable(false);
- viewClickable.setLongClickable(false);
- }
- viewClickable = decodeAreaOnClickListener(Card.CLICK_LISTENER_CONTENT_VIEW);
- if (viewClickable != null) {
+
+ viewClickable= decodeAreaOnClickListener(Card.CLICK_LISTENER_THUMBNAIL_VIEW);
+ if (viewClickable!=null)
viewClickable.setClickable(false);
- viewClickable.setLongClickable(false);
- }
- viewClickable = decodeAreaOnClickListener(Card.CLICK_LISTENER_EXPAND_VIEW);
- if (viewClickable != null) {
+
+ viewClickable= decodeAreaOnClickListener(Card.CLICK_LISTENER_CONTENT_VIEW);
+ if (viewClickable!=null)
viewClickable.setClickable(false);
- viewClickable.setLongClickable(false);
- }
}
/**
@@ -626,29 +578,25 @@ public class CardView extends BaseCardView {
* @param area
* @return
*/
- public View decodeAreaOnClickListener(int area){
+ protected View decodeAreaOnClickListener(int area){
- if (area < Card.CLICK_LISTENER_ALL_VIEW && area > Card.CLICK_LISTENER_CONTENT_VIEW) {
+ if (area<Card.CLICK_LISTENER_ALL_VIEW && area>Card.CLICK_LISTENER_CONTENT_VIEW)
return null;
- }
View view = null;
switch (area){
- case Card.CLICK_LISTENER_ALL_VIEW:
- view = this;
+ case Card.CLICK_LISTENER_ALL_VIEW :
+ view=this;
break;
- case Card.CLICK_LISTENER_HEADER_VIEW:
- view = mInternalHeaderLayout;
+ case Card.CLICK_LISTENER_HEADER_VIEW :
+ view=mInternalHeaderLayout;
break;
case Card.CLICK_LISTENER_THUMBNAIL_VIEW:
- view = mInternalThumbnailLayout;
+ view=mInternalThumbnailLayout;
break;
case Card.CLICK_LISTENER_CONTENT_VIEW:
- view = mInternalContentLayout;
- break;
- case Card.CLICK_LISTENER_EXPAND_VIEW:
- view = mInternalExpandLayout;
+ view=mInternalContentLayout;
break;
default:
break;
@@ -660,9 +608,6 @@ public class CardView extends BaseCardView {
// Expandable Actions and Listeners
//--------------------------------------------------------------------------
- protected int mCollapsedHeight;
- protected int mExpandedHeight=-1;
-
/**
* Add ClickListener to expand and collapse hidden view
*/
@@ -670,14 +615,16 @@ public class CardView extends BaseCardView {
if (mInternalExpandLayout != null) {
mInternalExpandLayout.setVisibility(View.GONE);
-
+ boolean internal_blockForLongClickOnImageButtonExpand = false;
ViewToClickToExpand viewToClickToExpand = null;
+ //ButtonExpandVisible has a priority to viewClickToExpand
if (mCardHeader != null && mCardHeader.isButtonExpandVisible()) {
viewToClickToExpand = ViewToClickToExpand.builder()
.setupView(mInternalHeaderLayout.getImageButtonExpand())
.highlightView(true);
+ internal_blockForLongClickOnImageButtonExpand = true;
} else if (mCard.getViewToClickToExpand() != null) {
@@ -688,13 +635,23 @@ public class CardView extends BaseCardView {
TitleViewOnClickListener titleViewOnClickListener = new TitleViewOnClickListener(mInternalExpandLayout, mCard, viewToClickToExpand.isViewToSelect());
- if (mCardHeader!=null && mCardHeader.isButtonExpandVisible() && mInternalHeaderLayout != null) {
+ /*if (mCardHeader!=null && mCardHeader.isButtonExpandVisible() && mInternalHeaderLayout != null) {
mInternalHeaderLayout.setOnClickExpandCollapseActionListener(titleViewOnClickListener);
- }
+ }*/
View viewToClick = viewToClickToExpand.getViewToClick();
if (viewToClick != null) {
- viewToClick.setOnClickListener(titleViewOnClickListener);
+
+ if (internal_blockForLongClickOnImageButtonExpand) {
+ //The long click on Header button is now allowed
+ viewToClick.setOnClickListener(titleViewOnClickListener);
+ }else{
+ if (viewToClickToExpand.isUseLongClick()){
+ viewToClick.setOnLongClickListener(new TitleViewOnLongClickListener(titleViewOnClickListener));
+ }else{
+ viewToClick.setOnClickListener(titleViewOnClickListener);
+ }
+ }
}else{
ViewToClickToExpand.CardElementUI cardElementUI=viewToClickToExpand.getCardElementUIToClick();
if (cardElementUI!=null){
@@ -713,7 +670,11 @@ public class CardView extends BaseCardView {
break;
}
if (viewToClick != null) {
- viewToClick.setOnClickListener(titleViewOnClickListener);
+ if (viewToClickToExpand.isUseLongClick()){
+ viewToClick.setOnLongClickListener(new TitleViewOnLongClickListener(titleViewOnClickListener));
+ }else{
+ viewToClick.setOnClickListener(titleViewOnClickListener);
+ }
}
}
}
@@ -765,6 +726,43 @@ public class CardView extends BaseCardView {
}
}
+ public void doToggleExpand() {
+
+ if (mInternalExpandLayout != null) {
+ ExpandContainerHelper helper = new ExpandContainerHelper(mInternalExpandLayout, mCard, false);
+
+ boolean isVisible = mInternalExpandLayout.getVisibility() == View.VISIBLE;
+ if (isVisible) {
+ ExpandCollapseHelper.animateCollapsing(helper);
+ } else {
+ ExpandCollapseHelper.animateExpanding(helper);
+ }
+ }
+ }
+
+ public void doExpand() {
+
+ if (mInternalExpandLayout != null) {
+ ExpandContainerHelper helper = new ExpandContainerHelper(mInternalExpandLayout, mCard, false);
+
+ boolean isVisible = mInternalExpandLayout.getVisibility() == View.VISIBLE;
+ if (!isVisible) {
+ ExpandCollapseHelper.animateExpanding(helper);
+ }
+ }
+ }
+
+ public void doCollapse() {
+
+ if (mInternalExpandLayout != null) {
+ ExpandContainerHelper helper = new ExpandContainerHelper(mInternalExpandLayout, mCard, false);
+
+ boolean isVisible = mInternalExpandLayout.getVisibility() == View.VISIBLE;
+ if (isVisible) {
+ ExpandCollapseHelper.animateCollapsing(helper);
+ }
+ }
+ }
/**
* Listener to expand/collapse hidden Expand Layout
@@ -772,71 +770,130 @@ public class CardView extends BaseCardView {
*/
protected class TitleViewOnClickListener implements View.OnClickListener {
- private View mContentParent;
- private Card mCard;
- private boolean viewToSelect=true;
+ ExpandContainerHelper mExpandContainerHelper;
private TitleViewOnClickListener(View contentParent,Card card) {
this (contentParent, card,true);
}
private TitleViewOnClickListener(View contentParent,Card card,boolean viewToSelect) {
- this.mContentParent = contentParent;
- this.mCard=card;
- this.viewToSelect=viewToSelect;
+ mExpandContainerHelper = new ExpandContainerHelper(contentParent, card, viewToSelect);
}
@Override
public void onClick(View view) {
- boolean isVisible = mContentParent.getVisibility() == View.VISIBLE;
+ boolean isVisible = mExpandContainerHelper.contentParent.getVisibility() == View.VISIBLE;
if (isVisible) {
- animateCollapsing();
- if (viewToSelect)
+ ExpandCollapseHelper.animateCollapsing(mExpandContainerHelper);
+ if (mExpandContainerHelper.viewToSelect)
view.setSelected(false);
} else {
- animateExpanding();
- if (viewToSelect)
+ ExpandCollapseHelper.animateExpanding(mExpandContainerHelper);
+ if (mExpandContainerHelper.viewToSelect)
view.setSelected(true);
}
}
+ }
+
+ /**
+ * Listener to expand/collapse hidden Expand Layout
+ * It starts animation
+ */
+ protected class TitleViewOnLongClickListener implements OnLongClickListener {
+
+ TitleViewOnClickListener mOnClickListener;
+
+ private TitleViewOnLongClickListener(TitleViewOnClickListener onClickListener) {
+ mOnClickListener = onClickListener;
+ }
+
+ @Override
+ public boolean onLongClick(View view) {
+ if (mOnClickListener != null){
+ mOnClickListener.onClick(view);
+ return true;
+ }
+ return false;
+ }
+ }
+
+ private class ExpandContainerHelper{
+
+ private View contentParent;
+ private Card card;
+ private boolean viewToSelect=true;
+
+ private ExpandContainerHelper(View contentParent, Card card, boolean viewToSelect) {
+ this.contentParent = contentParent;
+ this.card = card;
+ this.viewToSelect = viewToSelect;
+ }
+
+ public CardView getCardView() {
+ return (CardView) card.getCardView();
+ }
+ }
+
+ @Override
+ protected void onSizeChanged(int xNew, int yNew, int xOld, int yOld)
+ {
+ super.onSizeChanged(xNew, yNew, xOld, yOld);
+ }
+
+
+ private static class ExpandCollapseHelper {
/**
* Expanding animator.
*/
- private void animateExpanding() {
+ private static void animateExpanding(final ExpandContainerHelper helper) {
- if (getOnExpandListAnimatorListener()!=null){
+ //Callback
+ if (helper.card.getOnExpandAnimatorStartListener() != null)
+ helper.card.getOnExpandAnimatorStartListener().onExpandStart(helper.card);
+
+ if (helper.getCardView().getOnExpandListAnimatorListener()!=null){
//List Animator
- getOnExpandListAnimatorListener().onExpandStart(mCard.getCardView(), mContentParent);
+ helper.getCardView().getOnExpandListAnimatorListener().onExpandStart(helper.getCardView(), helper.contentParent);
}else{
//Std animator
- mContentParent.setVisibility(View.VISIBLE);
- mExpandAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mCard.setExpanded(true);
- //Callback
- if (mCard.getOnExpandAnimatorEndListener()!=null)
- mCard.getOnExpandAnimatorEndListener().onExpandEnd(mCard);
- }
- });
- mExpandAnimator.start();
+ helper.contentParent.setVisibility(View.VISIBLE);
+ if (helper.getCardView().mExpandAnimator != null) {
+ helper.getCardView().mExpandAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ helper.card.setExpanded(true);
+ //Callback
+ if (helper.card.getOnExpandAnimatorEndListener() != null)
+ helper.card.getOnExpandAnimatorEndListener().onExpandEnd(helper.card);
+ }
+ });
+ helper.getCardView().mExpandAnimator.start();
+ }else{
+ if (helper.card.getOnExpandAnimatorEndListener() != null)
+ helper.card.getOnExpandAnimatorEndListener().onExpandEnd(helper.card);
+ Log.w(TAG,"Does the card have the ViewToClickToExpand?");
+ }
}
}
/**
* Collapse animator
*/
- private void animateCollapsing() {
+ private static void animateCollapsing(final ExpandContainerHelper helper) {
+
+ //Callback
+ if (helper.card.getOnCollapseAnimatorStartListener() != null)
+ helper.card.getOnCollapseAnimatorStartListener().onCollapseStart(helper.card);
- if (getOnExpandListAnimatorListener()!=null){
+ if (helper.getCardView().getOnExpandListAnimatorListener() != null) {
//There is a List Animator.
- getOnExpandListAnimatorListener().onCollapseStart(mCard.getCardView(), mContentParent);
+ helper.getCardView().getOnExpandListAnimatorListener().onCollapseStart(helper.getCardView(), helper.contentParent);
}else{
//Std animator
- int origHeight = mContentParent.getHeight();
+ int origHeight = helper.contentParent.getHeight();
- ValueAnimator animator = createSlideAnimator(origHeight, 0);
+ ValueAnimator animator = createSlideAnimator(helper.getCardView(),origHeight, 0);
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
@@ -844,11 +901,11 @@ public class CardView extends BaseCardView {
@Override
public void onAnimationEnd(Animator animator) {
- mContentParent.setVisibility(View.GONE);
- mCard.setExpanded(false);
+ helper.contentParent.setVisibility(View.GONE);
+ helper.card.setExpanded(false);
//Callback
- if (mCard.getOnCollapseAnimatorEndListener()!=null)
- mCard.getOnCollapseAnimatorEndListener().onCollapseEnd(mCard);
+ if (helper.card.getOnCollapseAnimatorEndListener() != null)
+ helper.card.getOnCollapseAnimatorEndListener().onCollapseEnd(helper.card);
}
@Override
@@ -862,32 +919,27 @@ public class CardView extends BaseCardView {
animator.start();
}
}
- }
- /**
- * Create the Slide Animator invoked when the expand/collapse button is clicked
- */
- protected ValueAnimator createSlideAnimator(int start, int end) {
- ValueAnimator animator = ValueAnimator.ofInt(start, end);
- animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator valueAnimator) {
- int value = (Integer) valueAnimator.getAnimatedValue();
+ /**
+ * Create the Slide Animator invoked when the expand/collapse button is clicked
+ */
+ protected static ValueAnimator createSlideAnimator(final CardView cardView,int start, int end) {
+ ValueAnimator animator = ValueAnimator.ofInt(start, end);
- ViewGroup.LayoutParams layoutParams = mInternalExpandLayout.getLayoutParams();
- layoutParams.height = value;
- mInternalExpandLayout.setLayoutParams(layoutParams);
- }
- });
- return animator;
- }
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator valueAnimator) {
+ int value = (Integer) valueAnimator.getAnimatedValue();
+
+ ViewGroup.LayoutParams layoutParams = cardView.mInternalExpandLayout.getLayoutParams();
+ layoutParams.height = value;
+ cardView.mInternalExpandLayout.setLayoutParams(layoutParams);
+ }
+ });
+ return animator;
+ }
- @Override
- protected void onSizeChanged(int xNew, int yNew, int xOld, int yOld)
- {
- super.onSizeChanged(xNew, yNew, xOld, yOld);
- mExpandedHeight = yNew;
}
// -------------------------------------------------------------
@@ -895,14 +947,6 @@ public class CardView extends BaseCardView {
// -------------------------------------------------------------
/**
- * Interface to listen any callbacks when expand/collapse animation starts
- */
- public interface OnExpandListAnimatorListener {
- public void onExpandStart(CardView viewCard,View expandingLayout);
- public void onCollapseStart(CardView viewCard,View expandingLayout);
- }
-
- /**
* Returns the listener invoked when expand/collpase animation starts
* It is used internally
*
@@ -973,22 +1017,6 @@ public class CardView extends BaseCardView {
return mInternalInnerView;
}
- public int getCollapsedHeight() {
- return mCollapsedHeight;
- }
-
- public void setCollapsedHeight(int collapsedHeight) {
- mCollapsedHeight = collapsedHeight;
- }
-
- public int getExpandedHeight() {
- return mExpandedHeight;
- }
-
- public void setExpandedHeight(int expandedHeight) {
- mExpandedHeight = expandedHeight;
- }
-
/**
* Indicates if the card is expanded or collapsed
*
@@ -1012,6 +1040,11 @@ public class CardView extends BaseCardView {
}
}
+ @Override
+ public boolean isNative() {
+ return false;
+ }
+
/**
* Retrieves the InternalMainCardGlobalLayout.
* Background style is applied here.
@@ -1027,6 +1060,7 @@ public class CardView extends BaseCardView {
*
* @param drawableResourceId drawable resource Id
*/
+ @Override
public void changeBackgroundResourceId(int drawableResourceId) {
if (drawableResourceId!=0){
if (mInternalMainCardLayout!=null){
@@ -1040,14 +1074,17 @@ public class CardView extends BaseCardView {
*
* @param drawableResource drawable resource
*/
+ @Override
public void changeBackgroundResource(Drawable drawableResource) {
if (drawableResource!=null){
if (mInternalMainCardLayout!=null){
- if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
- mInternalMainCardLayout.setBackground(drawableResource);
- else
- mInternalMainCardLayout.setBackgroundDrawable(drawableResource);
+ mHelperImpl.setBackground(mInternalMainCardLayout, drawableResource);
}
}
}
+
+ @Override
+ public void changeBackgroundColorResourceId(int colorResourceId) {
+ //TODO : do nothing for now
+ }
}
diff --git a/src/it/gmariotti/cardslib/library/view/CardViewNative.java b/src/it/gmariotti/cardslib/library/view/CardViewNative.java
new file mode 100644
index 0000000..b241886
--- /dev/null
+++ b/src/it/gmariotti/cardslib/library/view/CardViewNative.java
@@ -0,0 +1,1271 @@
+/*
+ * ******************************************************************************
+ * Copyright (c) 2013-2014 Gabriele Mariotti.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * *****************************************************************************
+ */
+
+package com.android.cards.view;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.support.annotation.LayoutRes;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.widget.LinearLayout;
+
+import java.util.HashMap;
+
+import com.android.cards.R;
+import com.android.cards.internal.Card;
+import com.android.cards.internal.CardExpand;
+import com.android.cards.internal.CardHeader;
+import com.android.cards.internal.CardThumbnail;
+import com.android.cards.internal.ViewToClickToExpand;
+import com.android.cards.view.base.CardViewWrapper;
+import com.android.cards.view.component.CardHeaderView;
+import com.android.cards.view.component.CardThumbnailView;
+import com.android.cards.view.helper.CardViewHelper;
+import com.android.cards.view.helper.CardViewHelperUtil;
+import com.android.cards.view.listener.SwipeDismissViewTouchListener;
+
+/**
+* Card view
+* </p>
+* Use an XML layout file to display it.
+* </p>
+* First, you need an XML layout that will display the Card.
+* <pre><code>
+* <com.android.cards.view.CardViewNative
+* android:id="@+id/carddemo_example_card3"
+* android:layout_width="match_parent"
+* android:layout_height="wrap_content"
+* android:layout_marginLeft="12dp"
+* android:layout_marginRight="12dp"
+* android:layout_marginTop="12dp"/>
+* </code></pre>
+* Then create a model:
+* <pre><code>
+*
+* //Create a Card
+* Card card = new Card(getContext());
+*
+* //Create a CardHeader
+* CardHeader header = new CardHeader(getContext());
+*
+* //Add Header to card
+* card.addCardHeader(header);
+*
+* </code></pre>
+* Last get a reference to the `CardViewNative` from your code, and set your `Card.
+* <pre><code>
+* //Set card in the cardView
+* CardViewNative cardView = (CardViewNative) getActivity().findViewById(R.id.carddemo);
+*
+* cardView.setCard(card);
+* </code></pre>
+* You can easily build your layout.
+* </p>
+* The quickest way to start with this would be to copy one of this files and create your layout.
+* Then you can inflate your layout in the `CardViewNative` using the attr: `card:card_layout_resourceID="@layout/my_layout`
+* Example:
+* <pre><code>
+* <com.android.cards.view.CardViewNative
+* android:id="@+id/carddemo_thumb_url"
+* android:layout_width="match_parent"
+* android:layout_height="wrap_content"
+* android:layout_marginLeft="12dp"
+* android:layout_marginRight="12dp"
+* card:card_layout_resourceID="@layout/card_thumbnail_layout"
+* android:layout_marginTop="12dp"/>
+* </code></pre>
+* </p>
+* @author Gabriele Mariotti (gabri.mariotti@gmail.com)
+*/
+public class CardViewNative extends android.support.v7.widget.CardView implements CardViewWrapper {
+
+ protected static String TAG = "CardViewNative";
+
+ //--------------------------------------------------------------------------
+ // BaseCardView attribute
+ //--------------------------------------------------------------------------
+
+ /**
+ * Card Model
+ */
+ protected Card mCard;
+
+ /**
+ * Default layout to apply to card
+ */
+ protected @LayoutRes
+ int card_layout_resourceID = R.layout.native_card_layout;
+
+ /**
+ * Global View for this Component
+ */
+ protected View mInternalOuterView;
+
+
+ /**
+ * Header Compound View
+ */
+ protected CardHeaderView mInternalHeaderLayout;
+
+
+ /**
+ * Thumbnail Compound View
+ */
+ protected CardThumbnailView mInternalThumbnailLayout;
+
+ /**
+ * Used to recycle ui elements.
+ */
+ protected boolean mIsRecycle=false;
+
+ /**
+ * Used to replace inner layout elements.
+ */
+ protected boolean mForceReplaceInnerLayout =false;
+
+
+ protected CardViewHelper mHelperImpl;
+
+ //--------------------------------------------------------------------------
+ // CardView attribute
+ //--------------------------------------------------------------------------
+
+ /**
+ * {@link com.android.cards.internal.CardHeader} model
+ */
+ protected CardHeader mCardHeader;
+
+ /**
+ * {@link com.android.cards.internal.CardThumbnail} model
+ */
+ protected CardThumbnail mCardThumbnail;
+
+ /**
+ * {@link com.android.cards.internal.CardExpand} model
+ */
+ protected CardExpand mCardExpand;
+
+
+ //--------------------------------------------------------------------------
+ // Layout
+ //--------------------------------------------------------------------------
+
+
+ /**
+ * Main Layout
+ */
+ protected View mInternalMainCardLayout;
+
+ /**
+ * Content Layout
+ */
+ protected View mInternalContentLayout;
+
+ /**
+ * Inner View.
+ */
+ protected View mInternalInnerView;
+
+ /**
+ * Hidden layout used by expand/collapse action
+ */
+ protected View mInternalExpandLayout;
+
+ /**
+ * Expand Inner view
+ */
+ protected View mInternalExpandInnerView;
+
+
+ /** Animator to expand/collapse */
+ protected Animator mExpandAnimator;
+
+ /**
+ * Listener invoked when Expand Animator starts
+ * It is used internally
+ */
+ protected OnExpandListAnimatorListener mOnExpandListAnimatorListener;
+
+ //--------------------------------------------------------------------------
+ // Constructor
+ //--------------------------------------------------------------------------
+
+
+ public CardViewNative(Context context) {
+ this(context, null, 0);
+ }
+
+ public CardViewNative(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public CardViewNative(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(attrs, defStyleAttr);
+
+ mHelperImpl = CardViewHelperUtil.getInstance(context);
+ }
+
+ //--------------------------------------------------------------------------
+ // Init
+ //--------------------------------------------------------------------------
+
+ /**
+ * Initialize
+ *
+ * @param attrs
+ * @param defStyle
+ */
+ protected void init(AttributeSet attrs, int defStyle) {
+ //Init attrs
+ initAttrs(attrs, defStyle);
+
+ //Init view
+ if (!isInEditMode())
+ initView();
+ }
+
+ /**
+ * Init custom attrs.
+ *
+ * @param attrs
+ * @param defStyle
+ */
+ protected void initAttrs(AttributeSet attrs, int defStyle) {
+
+ card_layout_resourceID = R.layout.native_card_layout;
+
+ TypedArray a = getContext().getTheme().obtainStyledAttributes(
+ attrs, R.styleable.card_options, defStyle, defStyle);
+
+ try {
+ card_layout_resourceID = a.getResourceId(R.styleable.card_options_card_layout_resourceID, this.card_layout_resourceID);
+ } finally {
+ a.recycle();
+ }
+ }
+
+ /**
+ * Init View
+ */
+ protected void initView() {
+
+ //Inflate outer view
+ LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ mInternalOuterView = inflater.inflate(card_layout_resourceID, this, true);
+
+ //Radius
+ setRadius(getResources().getDimension(R.dimen.card_background_default_radius));
+
+
+
+ }
+
+
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ @Override
+ public void drawableHotspotChanged(float x, float y) {
+ super.drawableHotspotChanged(x, y);
+ if (mInternalMainCardLayout != null && mInternalMainCardLayout instanceof ForegroundLinearLayout) {
+ mInternalMainCardLayout.drawableHotspotChanged(x,y);
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ // Card
+ //--------------------------------------------------------------------------
+
+ /**
+ * Add a {@link Card}.
+ * It is very important to set all values and all components before launch this method.
+ *
+ * @param card {@link Card} model
+ */
+ @Override
+ public void setCard(Card card){
+
+ mCard = card;
+
+ if (card!=null){
+ mCardHeader=card.getCardHeader();
+ mCardThumbnail=card.getCardThumbnail();
+ mCardExpand=card.getCardExpand();
+ }
+
+ //Retrieve all IDs
+ if (!isRecycle()){
+ retrieveLayoutIDs();
+ }
+
+ //Build UI
+ buildUI();
+ }
+
+ /**
+ * Refreshes the card content (it doesn't inflate layouts again)
+ *
+ * @param card
+ */
+ public void refreshCard(Card card) {
+ mIsRecycle=true;
+ setCard(card);
+ mIsRecycle=false;
+ }
+
+ /**
+ * Refreshes the card content and replaces the inner layout elements (it inflates layouts again!)
+ *
+ * @param card
+ */
+ public void replaceCard(Card card) {
+ mForceReplaceInnerLayout=true;
+ refreshCard(card);
+ mForceReplaceInnerLayout=false;
+ }
+
+ //--------------------------------------------------------------------------
+ // Setup methods
+ //--------------------------------------------------------------------------
+
+ protected void buildUI() {
+
+ if (mCard == null) {
+ Log.e(TAG, "No card model found. Please use setCard(card) to set all values.");
+ return;
+ }
+ mCard.setCardView(this);
+
+ //Shadow
+ setupShadowView();
+
+ //Setup Header view
+ setupHeaderView();
+
+ //Setup Main View
+ setupMainView();
+
+ //setup Thumbnail
+ setupThumbnailView();
+
+ //Setup Expand View
+ setupExpandView();
+
+ //Setup Supplemental Actions
+ setupSupplementalActions();
+
+ //Setup Listeners
+ setupListeners();
+
+ //Setup Expand Action
+ setupExpandAction();
+
+ //Setup Drawable Resources
+ setupDrawableResources();
+ }
+
+
+ /**
+ * Retrieve all Layouts IDs
+ */
+ protected void retrieveLayoutIDs(){
+
+ //Main Layout
+ mInternalMainCardLayout = (View) findViewById(R.id.card_main_layout);
+
+ //Get HeaderLayout
+ mInternalHeaderLayout = (CardHeaderView) findViewById(R.id.card_header_layout);
+
+ //Get ExpandHiddenView
+ mInternalExpandLayout = (View) findViewById(R.id.card_content_expand_layout);
+
+ //Get ContentLayout
+ mInternalContentLayout = (View) findViewById(R.id.card_main_content_layout);
+
+ //Get ThumbnailLayout
+ mInternalThumbnailLayout = (CardThumbnailView) findViewById(R.id.card_thumbnail_layout);
+ }
+
+ /**
+ * Sets up Shadow visibility
+ *
+ * @return
+ */
+ protected void setupShadowView() {
+ if (mCard != null && mCard.getCardElevation() != null) {
+ this.setCardElevation(mCard.getCardElevation());
+ }
+ }
+
+ /**
+ * Setup Header View
+ */
+ protected void setupHeaderView(){
+
+ if (mCardHeader!=null){
+
+ if (mInternalHeaderLayout !=null){
+ mInternalHeaderLayout.setVisibility(VISIBLE);
+
+ //Set recycle value (very important in a ListView)
+ mInternalHeaderLayout.setRecycle(isRecycle());
+ mInternalHeaderLayout.setForceReplaceInnerLayout(isForceReplaceInnerLayout());
+ //Add Header View
+ mInternalHeaderLayout.addCardHeader(mCardHeader);
+
+ }
+ }else{
+ //No header. Hide layouts
+ if (mInternalHeaderLayout !=null){
+ mInternalHeaderLayout.setVisibility(GONE);
+ //mInternalExpandLayout.setVisibility(View.GONE);
+
+ if (isForceReplaceInnerLayout()){
+ mInternalHeaderLayout.addCardHeader(null);
+ //mInternalHeaderLayout.removeAllViews();
+ }
+ }
+ }
+ }
+
+ /**
+ * Setup the Main View
+ */
+ protected void setupMainView(){
+ if (mInternalContentLayout !=null){
+
+ ViewGroup mParentGroup=null;
+ try{
+ mParentGroup = (ViewGroup) mInternalContentLayout;
+ }catch (Exception e){
+ setRecycle(false);
+ }
+
+ //Check if view can be recycled
+ //It can happen in a listView, and improves performances
+ if (!isRecycle() || isForceReplaceInnerLayout()){
+
+ if (isForceReplaceInnerLayout() && mInternalContentLayout!=null && mInternalInnerView!=null)
+ ((ViewGroup)mInternalContentLayout).removeView(mInternalInnerView);
+
+ mInternalInnerView=mCard.getInnerView(getContext(), (ViewGroup) mInternalContentLayout);
+ }else{
+ //View can be recycled.
+ //Only setup Inner Elements
+ if (mCard.getInnerLayout()>-1)
+ mCard.setupInnerViewElements(mParentGroup,mInternalInnerView);
+ }
+ }
+ }
+
+
+ /**
+ * Setup the Thumbnail View
+ */
+ protected void setupThumbnailView() {
+ if (mInternalThumbnailLayout!=null){
+ if (mCardThumbnail!=null){
+ mInternalThumbnailLayout.setVisibility(VISIBLE);
+ mInternalThumbnailLayout.setRecycle(isRecycle());
+ mInternalThumbnailLayout.setForceReplaceInnerLayout(isForceReplaceInnerLayout());
+ mInternalThumbnailLayout.addCardThumbnail(mCardThumbnail);
+ }else{
+ mInternalThumbnailLayout.setVisibility(GONE);
+ }
+ }
+ }
+
+ /**
+ * Setup Drawable Resources
+ */
+ protected void setupDrawableResources() {
+
+ //Card
+ if (mCard!=null){
+ if (mCard.getBackgroundResourceId()!= Card.DEFAULT_COLOR){
+ changeBackgroundResourceId(mCard.getBackgroundResourceId());
+ }else if (mCard.getBackgroundResource()!=null){
+ changeBackgroundResource(mCard.getBackgroundResource());
+ }
+
+ if (mCard.getBackgroundColorResourceId() != Card.DEFAULT_COLOR){
+ changeBackgroundColorResourceId(mCard.getBackgroundColorResourceId());
+ }
+ }
+ }
+
+ protected void setupSupplementalActions() {
+ if (mCard != null)
+ mCard.setupSupplementalActions();
+ }
+
+ //--------------------------------------------------------------------------
+ // Listeners
+ //--------------------------------------------------------------------------
+
+ protected void setupExpandAction(){
+
+ //Config ExpandLayout and its animation
+ if ( mInternalExpandLayout !=null && ( (mCardHeader!=null && mCardHeader.isButtonExpandVisible()) ||
+ mCard.getViewToClickToExpand()!=null) ){
+
+ //Create the expand/collapse animator
+ mInternalExpandLayout.getViewTreeObserver().addOnPreDrawListener(
+ new ViewTreeObserver.OnPreDrawListener() {
+
+ @Override
+ public boolean onPreDraw() {
+ mInternalExpandLayout.getViewTreeObserver().removeOnPreDrawListener(this);
+
+ View parent = (View) mInternalExpandLayout.getParent();
+ final int widthSpec = View.MeasureSpec.makeMeasureSpec(parent.getMeasuredWidth() - parent.getPaddingLeft() - parent.getPaddingRight(), View.MeasureSpec.AT_MOST);
+ final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
+ mInternalExpandLayout.measure(widthSpec, heightSpec);
+
+ mExpandAnimator = ExpandCollapseHelper.createSlideAnimator((CardViewNative)mCard.getCardView(),0, mInternalExpandLayout.getMeasuredHeight());
+ return true;
+ }
+ });
+ }
+
+ //Setup action and callback
+ setupExpandCollapseActionListener();
+ }
+
+ /**
+ * Setup All listeners
+ */
+ @SuppressWarnings("deprecation")
+ @SuppressLint("NewApi")
+ protected void setupListeners(){
+
+ //Swipe listener
+ if (mCard.isSwipeable()){
+ this.setOnTouchListener(new SwipeDismissViewTouchListener(this, mCard,new SwipeDismissViewTouchListener.DismissCallbacks() {
+ @Override
+ public boolean canDismiss(Card card) {
+ return card.isSwipeable();
+ }
+
+ @Override
+ public void onDismiss(CardViewWrapper cardView, Card card) {
+ final ViewGroup vg = (ViewGroup)(((View)cardView).getParent());
+ if (vg!=null){
+ vg.removeView((View)cardView);
+ card.onSwipeCard();
+ }
+ }
+ }));
+ }else{
+ this.setOnTouchListener(null);
+ }
+
+ //OnClick listeners and partial listener
+
+ //Reset Partial Listeners
+ resetPartialListeners();
+
+ if (mCard.isClickable()){
+ //Set the onClickListener
+ if(!mCard.isMultiChoiceEnabled()){
+ if (mCard.getOnClickListener() != null) {
+ this.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mCard.getOnClickListener()!=null)
+ mCard.getOnClickListener().onClick(mCard,v);
+ }
+ });
+
+ //Prevent multiple events
+ //if (!mCard.isSwipeable() && mCard.getOnSwipeListener() == null) {
+ // this.setClickable(true);
+ //}
+
+ }else{
+ HashMap<Integer,Card.OnCardClickListener> mMultipleOnClickListner=mCard.getMultipleOnClickListener();
+ if (mMultipleOnClickListner!=null && !mMultipleOnClickListner.isEmpty()){
+
+ for (int key:mMultipleOnClickListner.keySet()){
+ View viewClickable= decodeAreaOnClickListener(key);
+ final Card.OnCardClickListener mListener=mMultipleOnClickListner.get(key);
+ if (viewClickable!=null){
+ //Add listener to this view
+ viewClickable.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ //Callback to card listener
+ if (mListener!=null)
+ mListener.onClick(mCard,v);
+ }
+ });
+
+ //Add Selector to this view
+ if (key > Card.CLICK_LISTENER_ALL_VIEW) {
+ mHelperImpl.setBackground(viewClickable, mHelperImpl.getResourceFromAttrs(getContext(),android.R.attr.selectableItemBackground));
+ }
+ }
+ }
+ }else{
+ //There aren't listners
+ this.setClickable(false);
+ }
+ }
+ }
+ }else{
+ this.setClickable(false);
+ }
+
+ //LongClick listener
+ if(mCard.isLongClickable()){
+ this.setOnLongClickListener(new OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ if (mCard.getOnLongClickListener()!=null)
+ return mCard.getOnLongClickListener().onLongClick(mCard,v);
+ return false;
+ }
+ });
+ }else{
+ this.setLongClickable(false);
+ }
+ }
+
+ /**
+ * Reset all partial listeners
+ */
+ protected void resetPartialListeners() {
+ View viewClickable= decodeAreaOnClickListener(Card.CLICK_LISTENER_HEADER_VIEW);
+ if (viewClickable!=null)
+ viewClickable.setClickable(false);
+
+ viewClickable= decodeAreaOnClickListener(Card.CLICK_LISTENER_THUMBNAIL_VIEW);
+ if (viewClickable!=null)
+ viewClickable.setClickable(false);
+
+ viewClickable= decodeAreaOnClickListener(Card.CLICK_LISTENER_CONTENT_VIEW);
+ if (viewClickable!=null)
+ viewClickable.setClickable(false);
+
+ viewClickable= decodeAreaOnClickListener(Card.CLICK_LISTENER_ACTIONAREA1_VIEW);
+ if (viewClickable!=null)
+ viewClickable.setClickable(false);
+ }
+
+ /**
+ *
+ * @param area
+ * @return
+ */
+ protected View decodeAreaOnClickListener(int area){
+
+ if (area<Card.CLICK_LISTENER_ALL_VIEW && area>Card.CLICK_LISTENER_CONTENT_VIEW)
+ return null;
+
+ View view = null;
+
+ switch (area){
+ case Card.CLICK_LISTENER_ALL_VIEW :
+ view=this;
+ break;
+ case Card.CLICK_LISTENER_HEADER_VIEW :
+ view=mInternalHeaderLayout;
+ break;
+ case Card.CLICK_LISTENER_THUMBNAIL_VIEW:
+ view=mInternalThumbnailLayout;
+ break;
+ case Card.CLICK_LISTENER_CONTENT_VIEW:
+ view=mInternalContentLayout;
+ break;
+ case Card.CLICK_LISTENER_ACTIONAREA1_VIEW:
+ view=mInternalMainCardLayout;
+ break;
+ default:
+ break;
+ }
+ return view;
+ }
+
+ //--------------------------------------------------------------------------
+ // Expandable Actions and Listeners
+ //--------------------------------------------------------------------------
+
+ /**
+ * Add ClickListener to expand and collapse hidden view
+ */
+ protected void setupExpandCollapseActionListener() {
+ if (mInternalExpandLayout != null) {
+ mInternalExpandLayout.setVisibility(View.GONE);
+
+ boolean internal_blockForLongClickOnImageButtonExpand = false;
+ ViewToClickToExpand viewToClickToExpand = null;
+
+ //ButtonExpandVisible has a priority to viewClickToExpand
+ if (mCardHeader != null && mCardHeader.isButtonExpandVisible()) {
+
+ viewToClickToExpand = ViewToClickToExpand.builder()
+ .setupView(mInternalHeaderLayout.getImageButtonExpand())
+ .highlightView(true);
+ internal_blockForLongClickOnImageButtonExpand = true;
+
+ } else if (mCard.getViewToClickToExpand() != null) {
+
+ viewToClickToExpand = mCard.getViewToClickToExpand();
+ }
+
+ if (viewToClickToExpand != null) {
+
+ TitleViewOnClickListener titleViewOnClickListener = new TitleViewOnClickListener(mInternalExpandLayout, mCard, viewToClickToExpand.isViewToSelect());
+
+ /*if (mCardHeader!=null && mCardHeader.isButtonExpandVisible() && mInternalHeaderLayout != null) {
+ mInternalHeaderLayout.setOnClickExpandCollapseActionListener(titleViewOnClickListener);
+ }*/
+
+ View viewToClick = viewToClickToExpand.getViewToClick();
+ if (viewToClick != null) {
+
+ if (internal_blockForLongClickOnImageButtonExpand) {
+ //The long click on Header button is now allowed
+ viewToClick.setOnClickListener(titleViewOnClickListener);
+ }else{
+ if (viewToClickToExpand.isUseLongClick()){
+ viewToClick.setOnLongClickListener(new TitleViewOnLongClickListener(titleViewOnClickListener));
+ }else{
+ viewToClick.setOnClickListener(titleViewOnClickListener);
+ }
+ }
+ }else{
+ ViewToClickToExpand.CardElementUI cardElementUI=viewToClickToExpand.getCardElementUIToClick();
+ if (cardElementUI!=null){
+ switch (cardElementUI){
+ case CARD:
+ viewToClick = this;
+ break;
+ case HEADER:
+ viewToClick = getInternalHeaderLayout();
+ break;
+ case THUMBNAIL:
+ viewToClick = getInternalThumbnailLayout();
+ break;
+ case MAIN_CONTENT:
+ viewToClick = getInternalContentLayout();
+ break;
+ }
+ if (viewToClick != null) {
+ if (viewToClickToExpand.isUseLongClick()){
+ viewToClick.setOnLongClickListener(new TitleViewOnLongClickListener(titleViewOnClickListener));
+ }else{
+ viewToClick.setOnClickListener(titleViewOnClickListener);
+ }
+ }
+ }
+ }
+
+ if (isExpanded()) {
+ //Make layout visible and button selected
+ mInternalExpandLayout.setVisibility(View.VISIBLE);
+ if (viewToClick != null) {
+ if (viewToClickToExpand.isViewToSelect())
+ viewToClick.setSelected(true);
+ }
+ } else {
+ //Make layout hidden and button not selected
+ mInternalExpandLayout.setVisibility(View.GONE);
+ if (viewToClick != null) {
+ if (viewToClickToExpand.isViewToSelect())
+ viewToClick.setSelected(false);
+ }
+ }
+ }
+
+ }
+ }
+
+ /**
+ * Listener to expand/collapse hidden Expand Layout
+ * It starts animation
+ */
+ protected class TitleViewOnLongClickListener implements OnLongClickListener {
+
+ TitleViewOnClickListener mOnClickListener;
+
+ private TitleViewOnLongClickListener(TitleViewOnClickListener onClickListener) {
+ mOnClickListener = onClickListener;
+ }
+
+ @Override
+ public boolean onLongClick(View view) {
+ if (mOnClickListener != null){
+ mOnClickListener.onClick(view);
+ return true;
+ }
+ return false;
+ }
+ }
+
+ private class ExpandContainerHelper{
+
+ private View contentParent;
+ private Card card;
+ private boolean viewToSelect=true;
+
+ private ExpandContainerHelper(View contentParent, Card card, boolean viewToSelect) {
+ this.contentParent = contentParent;
+ this.card = card;
+ this.viewToSelect = viewToSelect;
+ }
+
+ public CardViewNative getCardView() {
+ return (CardViewNative) card.getCardView();
+ }
+ }
+
+ private static class ExpandCollapseHelper {
+
+ /**
+ * Expanding animator.
+ */
+ private static void animateExpanding(final ExpandContainerHelper helper) {
+
+ if (helper.getCardView().getOnExpandListAnimatorListener()!=null){
+ //List Animator
+ helper.getCardView().getOnExpandListAnimatorListener().onExpandStart(helper.getCardView(), helper.contentParent);
+ }else{
+ //Std animator
+ helper.contentParent.setVisibility(View.VISIBLE);
+ if (helper.getCardView().mExpandAnimator != null) {
+ helper.getCardView().mExpandAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ helper.card.setExpanded(true);
+ //Callback
+ if (helper.card.getOnExpandAnimatorEndListener() != null)
+ helper.card.getOnExpandAnimatorEndListener().onExpandEnd(helper.card);
+ }
+ });
+ helper.getCardView().mExpandAnimator.start();
+ }else{
+ if (helper.card.getOnExpandAnimatorEndListener() != null)
+ helper.card.getOnExpandAnimatorEndListener().onExpandEnd(helper.card);
+ Log.w(TAG,"Does the card have the ViewToClickToExpand?");
+ }
+ }
+ }
+
+ /**
+ * Collapse animator
+ */
+ private static void animateCollapsing(final ExpandContainerHelper helper) {
+
+ if (helper.getCardView().getOnExpandListAnimatorListener()!=null){
+ //There is a List Animator.
+ helper.getCardView().getOnExpandListAnimatorListener().onCollapseStart(helper.getCardView(), helper.contentParent);
+ }else{
+ //Std animator
+ int origHeight = helper.contentParent.getHeight();
+
+ ValueAnimator animator = createSlideAnimator(helper.getCardView(),origHeight, 0);
+ animator.addListener(new Animator.AnimatorListener() {
+ @Override
+ public void onAnimationStart(Animator animator) {
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animator) {
+ helper.contentParent.setVisibility(View.GONE);
+ helper.card.setExpanded(false);
+ //Callback
+ if (helper.card.getOnCollapseAnimatorEndListener()!=null)
+ helper.card.getOnCollapseAnimatorEndListener().onCollapseEnd(helper.card);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animator) {
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animator) {
+ }
+ });
+ animator.start();
+ }
+ }
+
+
+ /**
+ * Create the Slide Animator invoked when the expand/collapse button is clicked
+ */
+ protected static ValueAnimator createSlideAnimator(final CardViewNative cardView,int start, int end) {
+ ValueAnimator animator = ValueAnimator.ofInt(start, end);
+
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator valueAnimator) {
+ int value = (Integer) valueAnimator.getAnimatedValue();
+
+ ViewGroup.LayoutParams layoutParams = cardView.mInternalExpandLayout.getLayoutParams();
+ layoutParams.height = value;
+ cardView.mInternalExpandLayout.setLayoutParams(layoutParams);
+ }
+ });
+ return animator;
+ }
+
+ }
+
+ /**
+ * Setup Expand View
+ */
+ protected void setupExpandView(){
+ if (mInternalExpandLayout!=null && mCardExpand!=null){
+
+ //Check if view can be recycled
+ //It can happen in a listView, and improves performances
+ if (!isRecycle() || isForceReplaceInnerLayout()){
+
+ if (isForceReplaceInnerLayout() && mInternalExpandLayout!=null && mInternalExpandInnerView!=null)
+ ((ViewGroup)mInternalExpandLayout).removeView(mInternalExpandInnerView);
+
+ mInternalExpandInnerView=mCardExpand.getInnerView(getContext(),(ViewGroup) mInternalExpandLayout);
+ }else{
+ //View can be recycled.
+ //Only setup Inner Elements
+ if (mCardExpand.getInnerLayout()>-1)
+ mCardExpand.setupInnerViewElements((ViewGroup)mInternalExpandLayout,mInternalExpandInnerView);
+ }
+
+ ViewGroup.LayoutParams layoutParams = mInternalExpandLayout.getLayoutParams();
+ layoutParams.height = LinearLayout.LayoutParams.WRAP_CONTENT;
+ mInternalExpandLayout.setLayoutParams(layoutParams);
+ }
+ }
+
+ public void doToggleExpand() {
+
+ if (mInternalExpandLayout != null) {
+ ExpandContainerHelper helper = new ExpandContainerHelper(mInternalExpandLayout, mCard, false);
+
+ boolean isVisible = mInternalExpandLayout.getVisibility() == View.VISIBLE;
+ if (isVisible) {
+ ExpandCollapseHelper.animateCollapsing(helper);
+ } else {
+ ExpandCollapseHelper.animateExpanding(helper);
+ }
+ }
+ }
+
+ public void doExpand() {
+
+ if (mInternalExpandLayout != null) {
+ ExpandContainerHelper helper = new ExpandContainerHelper(mInternalExpandLayout, mCard, false);
+
+ boolean isVisible = mInternalExpandLayout.getVisibility() == View.VISIBLE;
+ if (!isVisible) {
+ ExpandCollapseHelper.animateExpanding(helper);
+ }
+ }
+ }
+
+ public void doCollapse() {
+
+ if (mInternalExpandLayout != null) {
+ ExpandContainerHelper helper = new ExpandContainerHelper(mInternalExpandLayout, mCard, false);
+
+ boolean isVisible = mInternalExpandLayout.getVisibility() == View.VISIBLE;
+ if (isVisible) {
+ ExpandCollapseHelper.animateCollapsing(helper);
+ }
+ }
+ }
+
+ /**
+ * Listener to expand/collapse hidden Expand Layout
+ * It starts animation
+ */
+ protected class TitleViewOnClickListener implements View.OnClickListener {
+
+ ExpandContainerHelper mExpandContainerHelper;
+
+ private TitleViewOnClickListener(View contentParent,Card card) {
+ this (contentParent, card,true);
+ }
+
+ private TitleViewOnClickListener(View contentParent,Card card,boolean viewToSelect) {
+ mExpandContainerHelper = new ExpandContainerHelper(contentParent, card, viewToSelect);
+ }
+
+ @Override
+ public void onClick(View view) {
+ boolean isVisible = mExpandContainerHelper.contentParent.getVisibility() == View.VISIBLE;
+ if (isVisible) {
+ ExpandCollapseHelper.animateCollapsing(mExpandContainerHelper);
+ if (mExpandContainerHelper.viewToSelect)
+ view.setSelected(false);
+ } else {
+ ExpandCollapseHelper.animateExpanding(mExpandContainerHelper);
+ if (mExpandContainerHelper.viewToSelect)
+ view.setSelected(true);
+ }
+ }
+ }
+
+ @Override
+ protected void onSizeChanged(int xNew, int yNew, int xOld, int yOld)
+ {
+ super.onSizeChanged(xNew, yNew, xOld, yOld);
+ }
+
+ // -------------------------------------------------------------
+ // OnExpandListAnimator Interface and Listener
+ // -------------------------------------------------------------
+
+ /**
+ * Returns the listener invoked when expand/collpase animation starts
+ * It is used internally
+ *
+ * @return listener
+ */
+ public OnExpandListAnimatorListener getOnExpandListAnimatorListener() {
+ return mOnExpandListAnimatorListener;
+ }
+
+ /**
+ * Sets the listener invoked when expand/collapse animation starts
+ * It is used internally. Don't override it.
+ *
+ * @param onExpandListAnimatorListener listener
+ */
+ @Override
+ public void setOnExpandListAnimatorListener(CardViewWrapper.OnExpandListAnimatorListener onExpandListAnimatorListener) {
+ this.mOnExpandListAnimatorListener = onExpandListAnimatorListener;
+ }
+
+ // -------------------------------------------------------------
+ // ChangeBackground
+ // -------------------------------------------------------------
+
+ /**
+ * Changes dynamically the drawable resource to override the style of MainLayout.
+ *
+ * @param drawableResourceId drawable resource Id
+ */
+ @Override
+ public void changeBackgroundResourceId(int drawableResourceId) {
+ if (drawableResourceId!=Card.DEFAULT_COLOR){
+ changeBackgroundResource(getResources().getDrawable(drawableResourceId));
+ }
+ }
+
+ /**
+ * Changes dynamically the drawable resource to override the style of MainLayout.
+ *
+ * @param drawableResource drawable resource
+ */
+ @Override
+ public void changeBackgroundResource(Drawable drawableResource) {
+ if (drawableResource!=null){
+ if (mInternalMainCardLayout!=null){
+ mHelperImpl.setBackground(mInternalMainCardLayout, drawableResource);
+ }
+ }
+ }
+
+ /**
+ * Changes dynamically the color of the background card
+ *
+ * @param colorResourceId color resource Id
+ */
+ @Override
+ public void changeBackgroundColorResourceId(int colorResourceId) {
+ if (colorResourceId!=Card.DEFAULT_COLOR){
+ //this.setBackgroundDrawable(mHelperImpl.getResourceFromAttrs(getContext(),R.attr.cardBackgroundColor));
+ mInternalMainCardLayout.setBackgroundColor(getResources().getColor(colorResourceId));
+ }
+ }
+
+ // -------------------------------------------------------------
+ // Bitmap export
+ // -------------------------------------------------------------
+
+ /**
+ * Create a {@link android.graphics.Bitmap} from CardView
+ * @return
+ */
+ public Bitmap createBitmap(){
+
+ if (getWidth()<=0 && getHeight()<=0){
+ int spec = MeasureSpec.makeMeasureSpec( 0,MeasureSpec.UNSPECIFIED);
+ measure(spec,spec);
+ layout(0, 0, getMeasuredWidth(), getMeasuredHeight());
+ }
+
+ Bitmap b = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
+ Canvas c = new Canvas(b);
+ draw(c);
+ return b;
+ }
+
+ //--------------------------------------------------------------------------
+ // Getters and Setters
+ //--------------------------------------------------------------------------
+
+ public View getInternalOuterView() {
+ return mInternalOuterView;
+ }
+
+ /**
+ * Returns {@link Card} model
+ *
+ * @return {@link Card} model
+ */
+ public Card getCard() {
+ return mCard;
+ }
+
+ /**
+ * Returns the view used for Header
+ *
+ * @return {@link CardHeaderView}
+ */
+ public CardHeaderView getInternalHeaderLayout() {
+ return mInternalHeaderLayout;
+ }
+
+ /**
+ * Returns the view used by Thumbnail
+ *
+ * @return {@link CardThumbnailView}
+ */
+ @Override
+ public CardThumbnailView getInternalThumbnailLayout() {
+ return mInternalThumbnailLayout;
+ }
+
+ /**
+ * Indicates if view can recycle ui elements.
+ *
+ * @return <code>true</code> if views can recycle ui elements
+ */
+ public boolean isRecycle() {
+ return mIsRecycle;
+ }
+
+ /**
+ * Sets if view can recycle ui elements
+ *
+ * @param isRecycle <code>true</code> to recycle
+ */
+ @Override
+ public void setRecycle(boolean isRecycle) {
+ this.mIsRecycle = isRecycle;
+ }
+
+ /**
+ * Indicates if inner layout have to be replaced
+ *
+ * @return <code>true</code> if inner layout can be recycled
+ */
+ public boolean isForceReplaceInnerLayout() {
+ return mForceReplaceInnerLayout;
+ }
+
+ /**
+ * Sets if inner layout have to be replaced
+ *
+ * @param forceReplaceInnerLayout <code>true</code> to recycle
+ */
+ @Override
+ public void setForceReplaceInnerLayout(boolean forceReplaceInnerLayout) {
+ this.mForceReplaceInnerLayout = forceReplaceInnerLayout;
+ }
+
+ /**
+ * Returns the view used by Expand Layout
+ *
+ * @return {@link View} used by Expand Layout
+ */
+ public View getInternalExpandLayout() {
+ return mInternalExpandLayout;
+ }
+
+ /**
+ * FIXME
+ * @return
+ */
+ public View getInternalContentLayout() {
+ return mInternalContentLayout;
+ }
+
+ /**
+ * FIXME
+ * @return
+ */
+ public View getInternalInnerView() {
+ return mInternalInnerView;
+ }
+
+ /**
+ * Indicates if the card is expanded or collapsed
+ *
+ * @return <code>true</code> if the card is expanded
+ */
+ public boolean isExpanded() {
+ if (mCard!=null){
+ return mCard.isExpanded();
+ }else
+ return false;
+ }
+
+ /**
+ * Sets the card as expanded or collapsed
+ *
+ * @param expanded <code>true</code> if the card is expanded
+ */
+ public void setExpanded(boolean expanded) {
+ if (mCard!=null){
+ mCard.setExpanded(expanded);
+ }
+ }
+
+ @Override
+ public boolean isNative() {
+ return true;
+ }
+
+ /**
+ * Retrieves the InternalMainCardGlobalLayout.
+ *
+ * @return
+ */
+ public View getInternalMainCardLayout() {
+ return mInternalMainCardLayout;
+ }
+}
diff --git a/src/com/android/cards/view/ForegroundLinearLayout.java b/src/it/gmariotti/cardslib/library/view/ForegroundLinearLayout.java
index c5e769e..a991a70 100644
--- a/src/com/android/cards/view/ForegroundLinearLayout.java
+++ b/src/it/gmariotti/cardslib/library/view/ForegroundLinearLayout.java
@@ -19,11 +19,13 @@
package com.android.cards.view;
+import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.util.AttributeSet;
import android.view.Gravity;
import android.widget.LinearLayout;
@@ -220,4 +222,16 @@ public class ForegroundLinearLayout extends LinearLayout {
foreground.draw(canvas);
}
}
-}
+
+
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ @Override
+ public void drawableHotspotChanged(float x, float y) {
+ super.drawableHotspotChanged(x, y);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ if (mForeground != null) {
+ mForeground.setHotspot(x, y);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/com/android/cards/view/base/CardViewInterface.java b/src/it/gmariotti/cardslib/library/view/base/CardViewInterface.java
index 7f7d926..7f7d926 100644
--- a/src/com/android/cards/view/base/CardViewInterface.java
+++ b/src/it/gmariotti/cardslib/library/view/base/CardViewInterface.java
diff --git a/src/it/gmariotti/cardslib/library/view/base/CardViewWrapper.java b/src/it/gmariotti/cardslib/library/view/base/CardViewWrapper.java
new file mode 100644
index 0000000..09e6ecc
--- /dev/null
+++ b/src/it/gmariotti/cardslib/library/view/base/CardViewWrapper.java
@@ -0,0 +1,162 @@
+/*
+ * ******************************************************************************
+ * Copyright (c) 2013-2014 Gabriele Mariotti.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * *****************************************************************************
+ */
+
+package com.android.cards.view.base;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.view.View;
+
+import com.android.cards.internal.Card;
+import com.android.cards.view.component.CardThumbnailView;
+
+/**
+ * Common interface for CardView.
+ * <p>
+ * Necessary to merge the native cardview and the library cardview.
+ * <p>
+ * @author Gabriele Mariotti (gabri.mariotti@gmail.com)
+ */
+public interface CardViewWrapper {
+
+ /**
+ * Return the context
+ *
+ * @return context
+ */
+ Context getContext();
+
+ /**
+ * Expand the card
+ */
+ void doExpand();
+
+ /**
+ * Collapse the card
+ */
+ void doCollapse();
+
+ /**
+ * Toggle the card
+ */
+ void doToggleExpand();
+
+ /** Support for longClickable**/
+ void setLongClickable(boolean b);
+
+ /**
+ * Interface to listen any callbacks when expand/collapse animation starts
+ */
+ public interface OnExpandListAnimatorListener {
+ public void onExpandStart(CardViewWrapper viewCard,View expandingLayout);
+ public void onCollapseStart(CardViewWrapper viewCard,View expandingLayout);
+ }
+
+ /**
+ * Changes dynamically the drawable resource to override the style of MainLayout.
+ *
+ * @param drawableResourceId drawable resource Id
+ */
+ void changeBackgroundResourceId(int drawableResourceId);
+
+ /**
+ * Changes dynamically the drawable resource to override the style of MainLayout.
+ *
+ * @param drawableResource drawable resource
+ */
+ void changeBackgroundResource(Drawable drawableResource);
+
+ /**
+ * Changes dynamically the background color
+ *
+ * @param colorResourceId
+ */
+ void changeBackgroundColorResourceId(int colorResourceId);
+
+ /**
+ * Returns {@link Card} model
+ *
+ * @return {@link Card} model
+ */
+ Card getCard();
+
+ /**
+ * Add a {@link Card}.
+ * It is very important to set all values and all components before launch this method.
+ *
+ * @param card {@link Card} model
+ */
+ void setCard(Card card);
+
+ /**
+ * Indicates if inner layout have to be replaced
+ *
+ *
+ */
+ void setForceReplaceInnerLayout(boolean forceReplaceInnerLayout);
+
+ /**
+ * Sets if view can recycle ui elements
+ *
+ * @param recycle <code>true</code> to recycle
+ */
+ void setRecycle(boolean recycle);
+
+ /**
+ * Implement to refresh the card content (it doesn't inflate layouts again)
+ *
+ * @param card
+ */
+ void refreshCard(Card card);
+
+ /** Returns the view used by Thumbnail
+ *
+ * @return {@link CardThumbnailView}
+ */
+ CardThumbnailView getInternalThumbnailLayout();
+
+
+ void setOnTouchListener(View.OnTouchListener onTouchListener);
+
+ /**
+ * Sets the listener invoked when expand/collapse animation starts
+ * It is used internally. Don't override it.
+ *
+ * @param onExpandListAnimatorListener listener
+ */
+ void setOnExpandListAnimatorListener(OnExpandListAnimatorListener onExpandListAnimatorListener);
+
+ void setOnClickListener(View.OnClickListener advanceClickListener);
+
+ /**
+ * Sets the card as expanded or collapsed
+ *
+ * @param expanded <code>true</code> if the card is expanded
+ */
+ void setExpanded(boolean expanded);
+
+
+ boolean isNative();
+
+ /**
+ * Retrieves the InternalMainCardGlobalLayout.
+ *
+ * @return
+ */
+ View getInternalMainCardLayout();
+}
diff --git a/src/com/android/cards/view/component/CardHeaderView.java b/src/it/gmariotti/cardslib/library/view/component/CardHeaderView.java
index f409063..06cdf8f 100644
--- a/src/com/android/cards/view/component/CardHeaderView.java
+++ b/src/it/gmariotti/cardslib/library/view/component/CardHeaderView.java
@@ -21,7 +21,6 @@ package com.android.cards.view.component;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
-import android.os.Build;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MenuInflater;
@@ -35,6 +34,8 @@ import android.widget.PopupMenu;
import com.android.cards.R;
import com.android.cards.internal.CardHeader;
import com.android.cards.view.base.CardViewInterface;
+import com.android.cards.view.helper.CardViewHelper;
+import com.android.cards.view.helper.CardViewHelperUtil;
/**
* Compound View for Header Component.
@@ -123,7 +124,7 @@ public class CardHeaderView extends FrameLayout implements CardViewInterface {
/**
* Listener invoked when expand/collapse button is clicked
*/
- protected OnClickListener mOnClickExpandCollapseActionListener;
+ //protected OnClickListener mOnClickExpandCollapseActionListener;
/**
* Used to recycle ui elements.
@@ -140,23 +141,25 @@ public class CardHeaderView extends FrameLayout implements CardViewInterface {
*/
protected PopupMenu mPopupMenu;
+ protected CardViewHelper mHelperImpl;
+
//--------------------------------------------------------------------------
// Constructors
//--------------------------------------------------------------------------
public CardHeaderView(Context context) {
- super(context);
- init(null, 0);
+ this(context, null, 0);
}
public CardHeaderView(Context context, AttributeSet attrs) {
- super(context, attrs);
- init(attrs, 0);
+ this(context, attrs, 0);
}
public CardHeaderView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs, defStyle);
+
+ mHelperImpl = CardViewHelperUtil.getInstance(context);
}
//--------------------------------------------------------------------------
@@ -259,12 +262,11 @@ public class CardHeaderView extends FrameLayout implements CardViewInterface {
if (mCardHeader.isButtonOverflowVisible()) {
visibilityButtonHelper(VISIBLE, GONE, GONE);
- if (mCardHeader.getPopupMenu() != CardHeader.NO_POPUP_MENU) {
- //Add popup
- addPopup();
- } else if (mCardHeader.getCustomOverflowAnimation() != null) {
+ addPopup();
+ if (mPopupMenu==null && mCardHeader.getCustomOverflowAnimation() != null) {
addCustomOverflowAnimation();
}
+
} else {
if (mCardHeader.isButtonExpandVisible()) {
@@ -276,11 +278,7 @@ public class CardHeaderView extends FrameLayout implements CardViewInterface {
//Check if button is not null
if (mImageButtonOther != null) {
if (mCardHeader.getOtherButtonDrawable() > 0) {
- if (Build.VERSION.SDK_INT >= 16) {
- mImageButtonOther.setBackground(getResources().getDrawable(mCardHeader.getOtherButtonDrawable()));
- } else {
- mImageButtonOther.setBackgroundDrawable(getResources().getDrawable(mCardHeader.getOtherButtonDrawable()));
- }
+ mHelperImpl.setButtonBackground(mImageButtonOther, mCardHeader.getOtherButtonDrawable() );
}
addOtherListener();
}
@@ -370,16 +368,19 @@ public class CardHeaderView extends FrameLayout implements CardViewInterface {
protected void visibilityButtonHelper(int overflowButtonVisibility, int expandButtonVisibility, int otherButtonVisibility) {
if (overflowButtonVisibility == VISIBLE || overflowButtonVisibility == GONE) {
- if (mImageButtonOverflow != null)
+ if (mImageButtonOverflow != null) {
mImageButtonOverflow.setVisibility(overflowButtonVisibility);
+ }
}
if (expandButtonVisibility == VISIBLE || expandButtonVisibility == GONE) {
- if (mImageButtonExpand != null)
+ if (mImageButtonExpand != null) {
mImageButtonExpand.setVisibility(expandButtonVisibility);
+ }
}
if (otherButtonVisibility == VISIBLE || otherButtonVisibility == GONE) {
- if (mImageButtonOther != null)
+ if (mImageButtonOther != null) {
mImageButtonOther.setVisibility(otherButtonVisibility);
+ }
}
}
@@ -391,10 +392,10 @@ public class CardHeaderView extends FrameLayout implements CardViewInterface {
//To prevent recycle
mPopupMenu = null;
- if (mCardHeader.getPopupMenu() > -1 && mImageButtonOverflow != null) {
+ if (mImageButtonOverflow != null) {
// allow dynamic customization on popup menu
- boolean prepareMenu = true;
+ boolean prepareMenu = mCardHeader.getPopupMenu() > CardHeader.NO_POPUP_MENU ? true : false;
if (mCardHeader.getPopupMenuPrepareListener() != null) {
//Build the popupMenu
@@ -418,8 +419,10 @@ public class CardHeaderView extends FrameLayout implements CardViewInterface {
//PopupMenu is built inside onClick() method to avoid building the menu when it is not necessary
mPopupMenu = _buildPopupMenu();
}
- if (mPopupMenu!=null)
+ if (mPopupMenu!=null) {
mPopupMenu.show();
+ mImageButtonOverflow.setSelected(true);
+ }
}
});
} else {
@@ -442,12 +445,14 @@ public class CardHeaderView extends FrameLayout implements CardViewInterface {
private PopupMenu _buildPopupMenu(){
PopupMenu popup = new PopupMenu(getContext(), mImageButtonOverflow);
- MenuInflater inflater = popup.getMenuInflater();
- inflater.inflate(mCardHeader.getPopupMenu(), popup.getMenu());
+ if (mCardHeader.getPopupMenu()> CardHeader.NO_POPUP_MENU){
+ MenuInflater inflater = popup.getMenuInflater();
+ inflater.inflate(mCardHeader.getPopupMenu(), popup.getMenu());
+ }
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
- if (mCardHeader.getPopupMenu() > 0 && mCardHeader.getPopupMenuListener() != null) {
+ if (mCardHeader.getPopupMenuListener() != null) {
// This individual card has it unique menu
mCardHeader.getPopupMenuListener().onMenuItemClick(mCardHeader.getParentCard(), item);
}
@@ -455,6 +460,15 @@ public class CardHeaderView extends FrameLayout implements CardViewInterface {
}
});
+ popup.setOnDismissListener(new PopupMenu.OnDismissListener() {
+ @Override
+ public void onDismiss(PopupMenu menu) {
+ if (mImageButtonOverflow != null)
+ mImageButtonOverflow.setSelected(false);
+ }
+ });
+
+
return popup;
}
@@ -465,23 +479,23 @@ public class CardHeaderView extends FrameLayout implements CardViewInterface {
/**
* Returns Listener invoked when expand/collpse button is clicked
*
+ * @deprecated
* @return listener
*/
- public OnClickListener getOnClickExpandCollapseActionListener() {
+ /*public OnClickListener getOnClickExpandCollapseActionListener() {
return mOnClickExpandCollapseActionListener;
- }
+ }*/
/**
* Attaches Listener to expand/collapse button
*
+ * @deprecated
* @param onClickExpandCollapseActionListener listener
*/
- public void setOnClickExpandCollapseActionListener(OnClickListener onClickExpandCollapseActionListener) {
+ /*public void setOnClickExpandCollapseActionListener(OnClickListener onClickExpandCollapseActionListener) {
this.mOnClickExpandCollapseActionListener = onClickExpandCollapseActionListener;
- /*if (mImageButtonExpand != null)
- mImageButtonExpand.setOnClickListener(onClickExpandCollapseActionListener);
- */
- }
+
+ }*/
/**
* Indicates if view can recycle ui elements.
diff --git a/src/com/android/cards/view/component/CardShadowView.java b/src/it/gmariotti/cardslib/library/view/component/CardShadowView.java
index e367d33..e367d33 100644
--- a/src/com/android/cards/view/component/CardShadowView.java
+++ b/src/it/gmariotti/cardslib/library/view/component/CardShadowView.java
diff --git a/src/com/android/cards/view/component/CardThumbnailView.java b/src/it/gmariotti/cardslib/library/view/component/CardThumbnailView.java
index 43984c1..6f5b47b 100644
--- a/src/com/android/cards/view/component/CardThumbnailView.java
+++ b/src/it/gmariotti/cardslib/library/view/component/CardThumbnailView.java
@@ -174,13 +174,7 @@ public class CardThumbnailView extends FrameLayout implements CardViewInterface
//Get ImageVIew
mImageView= (ImageView) findViewById(R.id.card_thumbnail_image);
- }
- private void initLruCache() {
- mMemoryCache = CacheUtil.getMemoryCache();
- if (mMemoryCache != null) {
- return;
- }
// Get max available VM memory, exceeding this amount will throw an
// OutOfMemory exception. Stored in kilobytes as LruCache takes an
// int in its constructor.
@@ -189,20 +183,23 @@ public class CardThumbnailView extends FrameLayout implements CardViewInterface
// Use 1/8th of the available memory for this memory cache.
final int cacheSize = maxMemory / 8;
- mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
-
- @Override
- protected int sizeOf(String key, Bitmap bitmap) {
- // The cache size will be measured in kilobytes rather than
- // number of items.
- if (Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB_MR1) {
- return bitmap.getByteCount() / 1024;
- } else {
- return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
+ mMemoryCache = CacheUtil.getMemoryCache();
+ if (mMemoryCache==null){
+ mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
+
+ @Override
+ protected int sizeOf(String key, Bitmap bitmap) {
+ // The cache size will be measured in kilobytes rather than
+ // number of items.
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB_MR1) {
+ return bitmap.getByteCount() / 1024;
+ } else {
+ return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
+ }
}
- }
- };
- CacheUtil.putMemoryCache(mMemoryCache);
+ };
+ CacheUtil.putMemoryCache(mMemoryCache);
+ }
}
//--------------------------------------------------------------------------
@@ -245,15 +242,13 @@ public class CardThumbnailView extends FrameLayout implements CardViewInterface
mCardThumbnail.setupInnerViewElements((ViewGroup)mInternalOuterView,mImageView);
//Load bitmap
- if (!mCardThumbnail.isExternalUsage()) {
- initLruCache();
- if (mCardThumbnail.getCustomSource() != null) {
+ if (!mCardThumbnail.isExternalUsage()){
+ if (mCardThumbnail.getCustomSource() != null)
loadBitmap(mCardThumbnail.getCustomSource(), mImageView);
- } else if (mCardThumbnail.getDrawableResource() > 0) {
+ else if(mCardThumbnail.getDrawableResource()>0)
loadBitmap(mCardThumbnail.getDrawableResource(), mImageView);
- } else {
+ else
loadBitmap(mCardThumbnail.getUrlResource(), mImageView);
- }
}
}
@@ -436,24 +431,19 @@ public class CardThumbnailView extends FrameLayout implements CardViewInterface
return true;
}
- public static boolean cancelPotentialWork(
- CardThumbnail.CustomSource customSource, ImageView imageView) {
+ public static boolean cancelPotentialWork(CardThumbnail.CustomSource customSource, ImageView imageView) {
+ final BitmapWorkerCustomSourceTask bitmapWorkerTask = getBitmapWorkerCustomSourceTask(imageView);
- final BitmapWorkerCustomSourceTask bitmapWorkerTask =
- getBitmapWorkerCustomSourceTask(imageView);
-
- if (bitmapWorkerTask != null) {
-
- final CardThumbnail.CustomSource bitmapWorkerTaskCustomSource =
- bitmapWorkerTask.customSource;
-
- if (bitmapWorkerTaskCustomSource != null
- && !bitmapWorkerTaskCustomSource.getTag().equals(customSource.getTag())) {
- // Cancel previous task
- bitmapWorkerTask.cancel(true);
- } else {
- // The same work is already in progress
- return false;
+ if (bitmapWorkerTask != null && bitmapWorkerTask.customSource != null) {
+ final CardThumbnail.CustomSource bitmapWorkerTaskCustomSource = bitmapWorkerTask.customSource;
+ if (bitmapWorkerTaskCustomSource.getTag() != null) {
+ if (!bitmapWorkerTaskCustomSource.getTag().equals(customSource.getTag())) {
+ // Cancel previous task
+ bitmapWorkerTask.cancel(true);
+ } else {
+ // The same work is already in progress
+ return false;
+ }
}
}
// No task associated with the ImageView, or an existing task was cancelled
diff --git a/src/it/gmariotti/cardslib/library/view/helper/CardViewHelper.java b/src/it/gmariotti/cardslib/library/view/helper/CardViewHelper.java
new file mode 100644
index 0000000..7d7c215
--- /dev/null
+++ b/src/it/gmariotti/cardslib/library/view/helper/CardViewHelper.java
@@ -0,0 +1,54 @@
+/*
+ * ******************************************************************************
+ * Copyright (c) 2013-2014 Gabriele Mariotti.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * *****************************************************************************
+ */
+
+package com.android.cards.view.helper;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.view.View;
+import android.widget.ImageButton;
+
+/**
+ * @author Gabriele Mariotti (gabri.mariotti@gmail.com)
+ */
+public interface CardViewHelper {
+
+ /**
+ * Sets the background of the wiew
+ * @param view
+ * @param drawable
+ */
+ void setBackground(View view,Drawable drawable);
+
+ /**
+ * This method sets the button background for android api <L, while set the image source for android api >= L
+ * @param imageButton
+ * @param buttonDrawableResource
+ */
+ void setButtonBackground(ImageButton imageButton, int buttonDrawableResource);
+
+
+ void setCardSelector(View viewClickable, Drawable defaultDrawable);
+
+
+ void setElevation(View view,float elevation);
+
+
+ Drawable getResourceFromAttrs(Context themedContext, int attr);
+
+}
diff --git a/src/it/gmariotti/cardslib/library/view/helper/CardViewHelperImplBase.java b/src/it/gmariotti/cardslib/library/view/helper/CardViewHelperImplBase.java
new file mode 100644
index 0000000..c592878
--- /dev/null
+++ b/src/it/gmariotti/cardslib/library/view/helper/CardViewHelperImplBase.java
@@ -0,0 +1,82 @@
+/*
+ * ******************************************************************************
+ * Copyright (c) 2013-2014 Gabriele Mariotti.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * *****************************************************************************
+ */
+
+package com.android.cards.view.helper;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.support.v4.view.ViewCompat;
+import android.view.View;
+import android.widget.ImageButton;
+
+/**
+ * @author Gabriele Mariotti (gabri.mariotti@gmail.com)
+ */
+public class CardViewHelperImplBase implements CardViewHelper {
+
+ protected Context mContext;
+
+ public CardViewHelperImplBase(Context context){
+ mContext = context;
+ }
+
+ @Override
+ public void setBackground(View view, Drawable drawable) {
+ if (view != null)
+ view.setBackgroundDrawable(drawable);
+ }
+
+ @Override
+ public void setButtonBackground(ImageButton imageButton, int buttonDrawableResource) {
+ setBackground(imageButton, mContext.getResources().getDrawable(buttonDrawableResource));
+ }
+
+ @Override
+ public void setCardSelector(View viewClickable, Drawable defaultDrawable) {
+ setBackground(viewClickable, defaultDrawable);
+ }
+
+ @Override
+ public void setElevation(View view, float elevation) {
+ ViewCompat.setElevation(view, elevation);
+ }
+
+ @Override
+ public Drawable getResourceFromAttrs(Context themedContext, int attr){
+ // Create an array of the attributes we want to resolve
+ // using values from a theme
+ int[] attrs = new int[] { attr /* index 0 */};
+
+ // Obtain the styled attributes. 'themedContext' is a context with a
+ // theme, typically the current Activity (i.e. 'this')
+ TypedArray ta = themedContext.obtainStyledAttributes(attrs);
+
+ // To get the value of the 'listItemBackground' attribute that was
+ // set in the theme used in 'themedContext'. The parameter is the index
+ // of the attribute in the 'attrs' array. The returned Drawable
+ // is what you are after
+ Drawable drawableFromTheme = ta.getDrawable(0 /* index */);
+
+ // Finally, free the resources used by TypedArray
+ ta.recycle();
+
+ return drawableFromTheme;
+ }
+
+}
diff --git a/src/it/gmariotti/cardslib/library/view/helper/CardViewHelperImplJB.java b/src/it/gmariotti/cardslib/library/view/helper/CardViewHelperImplJB.java
new file mode 100644
index 0000000..e339c8e
--- /dev/null
+++ b/src/it/gmariotti/cardslib/library/view/helper/CardViewHelperImplJB.java
@@ -0,0 +1,49 @@
+/*
+ * ******************************************************************************
+ * Copyright (c) 2013-2014 Gabriele Mariotti.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * *****************************************************************************
+ */
+
+package com.android.cards.view.helper;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.view.View;
+import android.widget.ImageButton;
+
+/**
+ * @author Gabriele Mariotti (gabri.mariotti@gmail.com)
+ */
+@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
+public class CardViewHelperImplJB extends CardViewHelperImplBase {
+
+ public CardViewHelperImplJB(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void setBackground(View view, Drawable drawable) {
+ if (view != null)
+ view.setBackground(drawable);
+ }
+
+ @Override
+ public void setButtonBackground(ImageButton imageButton, int buttonDrawableResource) {
+ setBackground(imageButton, mContext.getResources().getDrawable(buttonDrawableResource));
+ }
+
+}
diff --git a/src/it/gmariotti/cardslib/library/view/helper/CardViewHelperImplKK.java b/src/it/gmariotti/cardslib/library/view/helper/CardViewHelperImplKK.java
new file mode 100644
index 0000000..8be05b7
--- /dev/null
+++ b/src/it/gmariotti/cardslib/library/view/helper/CardViewHelperImplKK.java
@@ -0,0 +1,36 @@
+/*
+ * ******************************************************************************
+ * Copyright (c) 2013-2014 Gabriele Mariotti.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * *****************************************************************************
+ */
+
+package com.android.cards.view.helper;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.os.Build;
+
+/**
+ * @author Gabriele Mariotti (gabri.mariotti@gmail.com)
+ */
+@TargetApi(Build.VERSION_CODES.KITKAT)
+public class CardViewHelperImplKK extends CardViewHelperImplJB{
+
+ public CardViewHelperImplKK(Context context) {
+ super(context);
+ }
+
+
+}
diff --git a/src/it/gmariotti/cardslib/library/view/helper/CardViewHelperImplL.java b/src/it/gmariotti/cardslib/library/view/helper/CardViewHelperImplL.java
new file mode 100644
index 0000000..3267439
--- /dev/null
+++ b/src/it/gmariotti/cardslib/library/view/helper/CardViewHelperImplL.java
@@ -0,0 +1,49 @@
+/*
+ * ******************************************************************************
+ * Copyright (c) 2013-2014 Gabriele Mariotti.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * *****************************************************************************
+ */
+
+package com.android.cards.view.helper;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.os.Build;
+import android.view.View;
+import android.widget.ImageButton;
+
+/**
+ * @author Gabriele Mariotti (gabri.mariotti@gmail.com)
+ */
+@TargetApi(Build.VERSION_CODES.LOLLIPOP)
+public class CardViewHelperImplL extends CardViewHelperImplKK {
+
+ public CardViewHelperImplL(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void setButtonBackground(ImageButton imageButton, int buttonDrawableResource) {
+ imageButton.setImageResource(buttonDrawableResource);
+ }
+
+ @Override
+ public void setElevation(View view, float elevation) {
+ if (view != null){
+ view.setElevation(elevation);
+ }
+ }
+
+}
diff --git a/src/it/gmariotti/cardslib/library/view/helper/CardViewHelperUtil.java b/src/it/gmariotti/cardslib/library/view/helper/CardViewHelperUtil.java
new file mode 100644
index 0000000..bceb1ec
--- /dev/null
+++ b/src/it/gmariotti/cardslib/library/view/helper/CardViewHelperUtil.java
@@ -0,0 +1,44 @@
+/*
+ * ******************************************************************************
+ * Copyright (c) 2013-2014 Gabriele Mariotti.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * *****************************************************************************
+ */
+
+package com.android.cards.view.helper;
+
+import android.content.Context;
+import android.os.Build;
+
+/**
+ * @author Gabriele Mariotti (gabri.mariotti@gmail.com)
+ */
+public class CardViewHelperUtil {
+
+
+ public static CardViewHelper getInstance(Context context){
+
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
+ return new CardViewHelperImplL(context);
+ } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {
+ return new CardViewHelperImplKK(context);
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+ return new CardViewHelperImplJB(context);
+ } else {
+ return new CardViewHelperImplBase(context);
+ }
+ }
+
+
+}
diff --git a/src/com/android/cards/view/listener/SwipeDismissListViewTouchListener.java b/src/it/gmariotti/cardslib/library/view/listener/SwipeDismissListViewTouchListener.java
index 7a7b83b..d39f53f 100644
--- a/src/com/android/cards/view/listener/SwipeDismissListViewTouchListener.java
+++ b/src/it/gmariotti/cardslib/library/view/listener/SwipeDismissListViewTouchListener.java
@@ -24,7 +24,6 @@ import android.animation.ValueAnimator;
import android.graphics.Rect;
import android.os.SystemClock;
import android.view.MotionEvent;
-import android.view.ScaleGestureDetector;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
@@ -37,8 +36,9 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import com.android.cards.R;
import com.android.cards.internal.Card;
-import com.android.cards.view.CardListView;
+import com.android.cards.view.listener.dismiss.Dismissable;
/**
* It is based on Roman Nurik code.
@@ -54,7 +54,7 @@ import com.android.cards.view.CardListView;
*
* <p>After creating the listener, the caller should also call
* {@link ListView#setOnScrollListener(AbsListView.OnScrollListener)}, using a
- * {@link it.gmariotti.cardslib.library.view.listener.SwipeOnScrollListener}.
+ * {@link com.android.cards.view.listener.SwipeOnScrollListener}.
*
* If a scroll listener is already assigned, the caller should still pass scroll changes through to this listener. This will
* ensure that this {@link SwipeDismissListViewTouchListener} is paused during list view
@@ -100,7 +100,6 @@ public class SwipeDismissListViewTouchListener implements View.OnTouchListener {
private float mDownX;
private float mDownY;
private boolean mSwiping;
- private boolean mSwipeInitialized;
private int mSwipingSlop;
private VelocityTracker mVelocityTracker;
private int mDownPosition;
@@ -108,9 +107,12 @@ public class SwipeDismissListViewTouchListener implements View.OnTouchListener {
private boolean mPaused;
/**
- * Custom gesture listener
+ * Dismissable Manager
*/
- protected ScaleGestureDetector mGestureDetector;
+ protected Dismissable mDismissable;
+
+
+ private int swipeDistanceDivisor = 2;
/**
* The callback interface used by {@link SwipeDismissListViewTouchListener} to inform its client
@@ -120,7 +122,7 @@ public class SwipeDismissListViewTouchListener implements View.OnTouchListener {
/**
* Called to determine whether the given position can be dismissed.
*/
- boolean canDismiss(int position, Card card);
+ boolean canDismiss(int position,Card card);
/**
* Called when the user has indicated they she would like to dismiss one or more list item
@@ -149,9 +151,7 @@ public class SwipeDismissListViewTouchListener implements View.OnTouchListener {
android.R.integer.config_shortAnimTime);
mListView = listView;
mCallbacks = callbacks;
- if (mListView instanceof CardListView) {
- mGestureDetector = ((CardListView) mListView).getGestureDetector();
- }
+ swipeDistanceDivisor = listView.getContext().getResources().getInteger(R.integer.list_card_swipe_distance_divisor);
}
/**
@@ -191,9 +191,6 @@ public class SwipeDismissListViewTouchListener implements View.OnTouchListener {
if (mViewWidth < 2) {
mViewWidth = mListView.getWidth();
}
- if (mGestureDetector != null && !mSwiping) {
- mGestureDetector.onTouchEvent(motionEvent);
- }
switch (motionEvent.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
@@ -210,12 +207,14 @@ public class SwipeDismissListViewTouchListener implements View.OnTouchListener {
// Find the child view that was touched (perform a hit test)
Rect rect = new Rect();
int childCount = mListView.getChildCount();
+ int headerCount = mListView.getHeaderViewsCount();
+ int footerCount = mListView.getFooterViewsCount();
int[] listViewCoords = new int[2];
mListView.getLocationOnScreen(listViewCoords);
int x = (int) motionEvent.getRawX() - listViewCoords[0];
int y = (int) motionEvent.getRawY() - listViewCoords[1];
- View child;
- for (int i = 0; i < childCount; i++) {
+ View child=null;
+ for (int i = headerCount; i < (childCount - footerCount); i++) {
child = mListView.getChildAt(i);
child.getHitRect(rect);
if (rect.contains(x, y)) {
@@ -225,42 +224,28 @@ public class SwipeDismissListViewTouchListener implements View.OnTouchListener {
}
if (mDownView != null) {
+
mDownX = motionEvent.getRawX();
mDownY = motionEvent.getRawY();
mDownPosition = mListView.getPositionForView(mDownView);
- if (mCallbacks.canDismiss(mDownPosition,
- (Card) mListView.getAdapter().getItem(mDownPosition))) {
- mVelocityTracker = VelocityTracker.obtain();
- mVelocityTracker.addMovement(motionEvent);
- } else {
+ if (mDownPosition != ListView.INVALID_POSITION && mDownPosition < mListView.getAdapter().getCount()) {
+ if (mListView.getAdapter().getItem(mDownPosition) instanceof Card) {
+ if (mCallbacks.canDismiss(mDownPosition, (Card) mListView.getAdapter().getItem(mDownPosition))) {
+ mVelocityTracker = VelocityTracker.obtain();
+ mVelocityTracker.addMovement(motionEvent);
+ } else {
+ mDownView = null;
+ }
+ } else {
+ mDownView = null;
+ }
+ }else{
mDownView = null;
}
}
- return false;
- }
-
- case MotionEvent.ACTION_CANCEL: {
- if (mVelocityTracker == null) {
- break;
- }
-
- if (mDownView != null && mSwiping) {
- // cancel
- mDownView.animate()
- .translationX(0)
- .alpha(1)
- .setDuration(mAnimationTime)
- .setListener(null);
- }
- mVelocityTracker.recycle();
- mVelocityTracker = null;
- mDownX = 0;
- mDownY = 0;
- mDownView = null;
- mDownPosition = ListView.INVALID_POSITION;
- mSwipeInitialized = false;
- mSwiping = false;
- break;
+ view.onTouchEvent(motionEvent);
+ return true;
+ //return false;
}
case MotionEvent.ACTION_UP: {
@@ -276,7 +261,7 @@ public class SwipeDismissListViewTouchListener implements View.OnTouchListener {
float absVelocityY = Math.abs(mVelocityTracker.getYVelocity());
boolean dismiss = false;
boolean dismissRight = false;
- if (Math.abs(deltaX) > mViewWidth / 2 && mSwiping) {
+ if (Math.abs(deltaX) > mViewWidth / swipeDistanceDivisor && mSwiping) {
dismiss = true;
dismissRight = deltaX > 0;
} else if (mMinFlingVelocity <= absVelocityX && absVelocityX <= mMaxFlingVelocity
@@ -287,19 +272,8 @@ public class SwipeDismissListViewTouchListener implements View.OnTouchListener {
}
if (dismiss && mDownPosition != ListView.INVALID_POSITION) {
// dismiss
- final View downView = mDownView; // mDownView gets null'd before animation ends
- final int downPosition = mDownPosition;
- ++mDismissAnimationRefCount;
- mDownView.animate()
- .translationX(dismissRight ? mViewWidth : -mViewWidth)
- .alpha(0)
- .setDuration(mAnimationTime)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- performDismiss(downView, downPosition);
- }
- });
+ dismiss(mDownView, mDownPosition - mListView.getHeaderViewsCount(), dismissRight);
+
} else {
// cancel
mDownView.animate()
@@ -308,15 +282,15 @@ public class SwipeDismissListViewTouchListener implements View.OnTouchListener {
.setDuration(mAnimationTime)
.setListener(null);
}
+
mVelocityTracker.recycle();
mVelocityTracker = null;
mDownX = 0;
mDownY = 0;
mDownView = null;
mDownPosition = ListView.INVALID_POSITION;
- mSwipeInitialized = false;
- if (mSwiping) {
- // To prevent onClick event with a fast swipe
+ if (mSwiping){
+ //To prevent onClick event with a fast swipe
mSwiping = false;
return true;
}
@@ -324,6 +298,29 @@ public class SwipeDismissListViewTouchListener implements View.OnTouchListener {
break;
}
+ case MotionEvent.ACTION_CANCEL: {
+ if (mVelocityTracker == null) {
+ break;
+ }
+
+ if (mDownView != null) {
+ // cancel
+ mDownView.animate()
+ .translationX(0)
+ .alpha(1)
+ .setDuration(mAnimationTime)
+ .setListener(null);
+ }
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ mDownX = 0;
+ mDownY = 0;
+ mDownView = null;
+ mDownPosition = ListView.INVALID_POSITION;
+ mSwiping = false;
+ break;
+ }
+
case MotionEvent.ACTION_MOVE: {
if (mVelocityTracker == null || mPaused) {
break;
@@ -332,12 +329,10 @@ public class SwipeDismissListViewTouchListener implements View.OnTouchListener {
mVelocityTracker.addMovement(motionEvent);
float deltaX = motionEvent.getRawX() - mDownX;
float deltaY = motionEvent.getRawY() - mDownY;
- if (Math.abs(deltaX) > mSlop && Math.abs(deltaY) < Math.abs(deltaX) / 2) {
+ boolean movementAllowed = isSwipeMovementAllowed(deltaX);
+ if (Math.abs(deltaX) > mSlop && Math.abs(deltaY) < Math.abs(deltaX) / 2 && movementAllowed) {
mSwiping = true;
- if (!mSwipeInitialized) {
- mSwipeInitialized = true;
- mSwipingSlop = (deltaX > 0 ? mSlop : -mSlop);
- }
+ mSwipingSlop = (deltaX > 0 ? mSlop : -mSlop);
mListView.requestDisallowInterceptTouchEvent(true);
// Cancel ListView's touch (un-highlighting the item)
@@ -362,6 +357,28 @@ public class SwipeDismissListViewTouchListener implements View.OnTouchListener {
return false;
}
+ private void dismiss(final View view, final int position, boolean dismissRight) {
+ ++mDismissAnimationRefCount;
+ if (view == null) {
+ // No view, shortcut to calling onDismiss to let it deal with adapter
+ // updates and all that.
+ mCallbacks.onDismiss(mListView, new int[] { position });
+ return;
+ }
+
+ view.animate()
+ .translationX(dismissRight ? mViewWidth : -mViewWidth)
+ .alpha(0)
+ .setDuration(mAnimationTime)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ performDismiss(view, position);
+ }
+ });
+ }
+
+
class PendingDismissData implements Comparable<PendingDismissData> {
public int position;
public View view;
@@ -439,4 +456,25 @@ public class SwipeDismissListViewTouchListener implements View.OnTouchListener {
mPendingDismisses.add(new PendingDismissData(dismissPosition, dismissView));
animator.start();
}
-}
+
+ private boolean isSwipeMovementAllowed(float deltaX) {
+ switch (mDismissable.getSwipeDirectionAllowed()) {
+ case BOTH:
+ return Math.abs(deltaX) > 0;
+ case RIGHT:
+ return deltaX > 0;
+ case LEFT:
+ return deltaX < 0;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Sets a custom DismissableManager
+ * @param dismissable
+ */
+ public void setDismissable(Dismissable dismissable) {
+ mDismissable = dismissable;
+ }
+} \ No newline at end of file
diff --git a/src/it/gmariotti/cardslib/library/view/listener/SwipeDismissTopBottomTouchListener.java b/src/it/gmariotti/cardslib/library/view/listener/SwipeDismissTopBottomTouchListener.java
new file mode 100644
index 0000000..4335684
--- /dev/null
+++ b/src/it/gmariotti/cardslib/library/view/listener/SwipeDismissTopBottomTouchListener.java
@@ -0,0 +1,285 @@
+/*
+ * ******************************************************************************
+ * Copyright (c) 2014 Gabriele Mariotti.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * *****************************************************************************
+ */
+
+package com.android.cards.view.listener;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+
+/**
+ * A {@link android.view.View.OnTouchListener} that makes any {@link android.view.View} dismissable when the
+ * user swipes (drags her finger) horizontally across the view.
+ *
+ * <p><em>For {@link android.widget.ListView} list items that don't manage their own touch events
+ * (i.e. you're using
+ * {@link android.widget.ListView#setOnItemClickListener(android.widget.AdapterView.OnItemClickListener)}
+ * or an equivalent listener on {@link android.app.ListActivity} or
+ * {@link android.app.ListFragment}, use {@link com.android.cards.view.listener.SwipeDismissListViewTouchListener} instead.</em></p>
+ *
+ * <p>Example usage:</p>
+ *
+ * <pre>
+ * view.setOnTouchListener(new SwipeDismissTouchListener(
+ * view,
+ * null, // Optional token/cookie object
+ * new SwipeDismissTouchListener.OnDismissCallback() {
+ * public void onDismiss(View view, Object token) {
+ * parent.removeView(view);
+ * }
+ * }));
+ * </pre>
+ *
+ * <p>This class Requires API level 12 or later due to use of {@link
+ * android.view.ViewPropertyAnimator}.</p>
+ *
+ * @see com.android.cards.view.listener.SwipeDismissListViewTouchListener
+ */
+public class SwipeDismissTopBottomTouchListener implements View.OnTouchListener {
+
+ // Cached ViewConfiguration and system-wide constant values
+ private int mSlop;
+ private int mMinFlingVelocity;
+ private int mMaxFlingVelocity;
+ private long mAnimationTime;
+
+ // Fixed properties
+ private View mView;
+ private DismissCallbacks mCallbacks;
+ private int mViewHeight = 1; // 1 and not 0 to prevent dividing by zero
+
+ // Transient properties
+ private float mDownX;
+ private float mDownY;
+ private boolean mSwiping;
+ private int mSwipingSlop;
+ private Object mToken;
+ private VelocityTracker mVelocityTracker;
+ private float mTranslationY;
+ private float mOriginalY;
+
+ /**
+ * The callback interface used by {@link com.android.cards.view.listener.SwipeDismissTopBottomTouchListener} to inform its client
+ * about a successful dismissal of the view for which it was created.
+ */
+ public interface DismissCallbacks {
+ /**
+ * Called to determine whether the view can be dismissed.
+ */
+ boolean canDismiss(Object token);
+
+ /**
+ * Called when the user has indicated they she would like to dismiss the view.
+ *
+ * @param view The originating {@link android.view.View} to be dismissed.
+ * @param token The optional token passed to this object's constructor.
+ */
+ void onDismiss(View view, Object token);
+ }
+
+ /**
+ * Constructs a new swipe-to-dismiss touch listener for the given view.
+ *
+ * @param view The view to make dismissable.
+ * @param token An optional token/cookie object to be passed through to the callback.
+ * @param callbacks The callback to trigger when the user has indicated that she would like to
+ * dismiss this view.
+ */
+ public SwipeDismissTopBottomTouchListener(View view, Object token, DismissCallbacks callbacks) {
+ ViewConfiguration vc = ViewConfiguration.get(view.getContext());
+ mSlop = 0;
+ mMinFlingVelocity = vc.getScaledMinimumFlingVelocity() * 16;
+ mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity();
+ mAnimationTime = view.getContext().getResources().getInteger(
+ android.R.integer.config_shortAnimTime);
+ mView = view;
+ mToken = token;
+ mCallbacks = callbacks;
+ }
+
+ @Override
+ public boolean onTouch(View view, MotionEvent motionEvent) {
+ // offset because the view is translated during swipe
+ motionEvent.offsetLocation(0, mTranslationY);
+
+ if (mViewHeight < 2) {
+ mViewHeight = mView.getHeight();
+ }
+
+ if (mOriginalY == 0){
+ mOriginalY = mView.getY();
+ }
+
+ switch (motionEvent.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN: {
+ // TODO: ensure this is a finger, and set a flag
+ mDownX = motionEvent.getRawX();
+ mDownY = motionEvent.getRawY();
+ if (mCallbacks.canDismiss(mToken)) {
+ mVelocityTracker = VelocityTracker.obtain();
+ mVelocityTracker.addMovement(motionEvent);
+ }
+ view.onTouchEvent(motionEvent);
+ return true;
+ }
+
+ case MotionEvent.ACTION_UP: {
+ if (mVelocityTracker == null) {
+ break;
+ }
+
+ float deltaY = motionEvent.getRawY() - mDownY;
+ mVelocityTracker.addMovement(motionEvent);
+ mVelocityTracker.computeCurrentVelocity(1000);
+ float velocityX = mVelocityTracker.getXVelocity();
+ float absVelocityX = Math.abs(velocityX);
+ float absVelocityY = Math.abs(mVelocityTracker.getYVelocity());
+ boolean dismiss = false;
+ boolean dismissRight = false;
+ if (Math.abs(deltaY) > 2 * mViewHeight / 3 && mSwiping) {
+ dismiss = true;
+ dismissRight = deltaY > 0;
+ } else if (mMinFlingVelocity <= absVelocityX && absVelocityX <= mMaxFlingVelocity
+ && absVelocityY < absVelocityX
+ && mSwiping) {
+ // dismiss only if flinging in the same direction as dragging
+ dismiss = (velocityX < 0) == (deltaY < 0);
+ dismissRight = mVelocityTracker.getXVelocity() > 0;
+ }
+ if (dismiss) {
+ // dismiss
+ mView.animate()
+ .translationY(dismissRight ? mViewHeight : -mViewHeight)
+ .alpha(0)
+ .setDuration(mAnimationTime)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ performDismiss();
+ }
+ });
+ } else if (mSwiping) {
+ // cancel
+ mView.animate()
+ .translationY(0)
+ .alpha(1)
+ .setDuration(mAnimationTime)
+ .setListener(null);
+ }
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ mTranslationY = 0;
+ mDownX = 0;
+ mDownY = 0;
+ mSwiping = false;
+ break;
+ }
+
+ case MotionEvent.ACTION_CANCEL: {
+ if (mVelocityTracker == null) {
+ break;
+ }
+
+ mView.animate()
+ .translationY(0)
+ .alpha(1)
+ .setDuration(mAnimationTime)
+ .setListener(null);
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ mTranslationY = 0;
+ mDownX = 0;
+ mDownY = 0;
+ mSwiping = false;
+ break;
+ }
+
+ case MotionEvent.ACTION_MOVE: {
+ if (mVelocityTracker == null) {
+ break;
+ }
+
+ mVelocityTracker.addMovement(motionEvent);
+ float deltaX = motionEvent.getRawX() - mDownX;
+ float deltaY = motionEvent.getRawY() - mDownY;
+ if (Math.abs(deltaY) > mSlop && Math.abs(deltaX) < Math.abs(deltaY) / 2 & deltaY > 0) {
+ mSwiping = true;
+ mSwipingSlop = (deltaY > 0 ? mSlop : 0);
+ mView.getParent().requestDisallowInterceptTouchEvent(true);
+
+ // Cancel listview's touch
+ MotionEvent cancelEvent = MotionEvent.obtain(motionEvent);
+ cancelEvent.setAction(MotionEvent.ACTION_CANCEL |
+ (motionEvent.getActionIndex() <<
+ MotionEvent.ACTION_POINTER_INDEX_SHIFT));
+ mView.onTouchEvent(cancelEvent);
+ cancelEvent.recycle();
+ }
+
+ if (mSwiping) {
+ mTranslationY = deltaY >=0 ? deltaY : 0;
+ mView.setTranslationY( deltaY >=0 ? deltaY - mSwipingSlop: 0);
+ // TODO: use an ease-out interpolator or such
+ mView.setAlpha(deltaY >=0 ? Math.max(0f, Math.min(1f,
+ 1f - 1.5f * Math.abs(deltaY) / mViewHeight)): 1f);
+ return true;
+ }
+ break;
+ }
+ }
+ return false;
+ }
+
+ private void performDismiss() {
+ // Animate the dismissed view to zero-height and then fire the dismiss callback.
+ // This triggers layout on each animation frame; in the future we may want to do something
+ // smarter and more performant.
+
+ final ViewGroup.LayoutParams lp = mView.getLayoutParams();
+ final int originalHeight = mView.getHeight();
+
+ ValueAnimator animator = ValueAnimator.ofInt(originalHeight, 1).setDuration(mAnimationTime);
+
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mCallbacks.onDismiss(mView, mToken);
+ // Reset view presentation
+ mView.setAlpha(1f);
+ mView.setTranslationY(0);
+ lp.height = originalHeight;
+ mView.setLayoutParams(lp);
+ }
+ });
+
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator valueAnimator) {
+ lp.height = (Integer) valueAnimator.getAnimatedValue();
+ mView.setLayoutParams(lp);
+ }
+ });
+
+ animator.start();
+ }
+} \ No newline at end of file
diff --git a/src/it/gmariotti/cardslib/library/view/listener/SwipeDismissTouchListener.java b/src/it/gmariotti/cardslib/library/view/listener/SwipeDismissTouchListener.java
new file mode 100644
index 0000000..f9ebdd7
--- /dev/null
+++ b/src/it/gmariotti/cardslib/library/view/listener/SwipeDismissTouchListener.java
@@ -0,0 +1,284 @@
+/*
+ * ******************************************************************************
+ * Copyright (c) 2014 Google Inc., Gabriele Mariotti.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * *****************************************************************************
+ */
+
+package com.android.cards.view.listener;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.app.ListActivity;
+import android.app.ListFragment;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ListView;
+
+/**
+ * A {@link View.OnTouchListener} that makes any {@link View} dismissable when the
+ * user swipes (drags her finger) horizontally across the view.
+ *
+ * <p><em>For {@link ListView} list items that don't manage their own touch events
+ * (i.e. you're using
+ * {@link ListView#setOnItemClickListener(AdapterView.OnItemClickListener)}
+ * or an equivalent listener on {@link ListActivity} or
+ * {@link ListFragment}, use {@link SwipeDismissListViewTouchListener} instead.</em></p>
+ *
+ * <p>Example usage:</p>
+ *
+ * <pre>
+ * view.setOnTouchListener(new SwipeDismissTouchListener(
+ * view,
+ * null, // Optional token/cookie object
+ * new SwipeDismissTouchListener.OnDismissCallback() {
+ * public void onDismiss(View view, Object token) {
+ * parent.removeView(view);
+ * }
+ * }));
+ * </pre>
+ *
+ * <p>This class Requires API level 12 or later due to use of {@link
+ * android.view.ViewPropertyAnimator}.</p>
+ *
+ * @see SwipeDismissListViewTouchListener
+ */
+public class SwipeDismissTouchListener implements View.OnTouchListener {
+
+ // Cached ViewConfiguration and system-wide constant values
+ private int mSlop;
+ private int mMinFlingVelocity;
+ private int mMaxFlingVelocity;
+ private long mAnimationTime;
+
+ // Fixed properties
+ private View mView;
+ private DismissCallbacks mCallbacks;
+ private int mViewWidth = 1; // 1 and not 0 to prevent dividing by zero
+
+ // Transient properties
+ private float mDownX;
+ private float mDownY;
+ private boolean mSwiping;
+ private int mSwipingSlop;
+ private Object mToken;
+ private VelocityTracker mVelocityTracker;
+ private float mTranslationX;
+
+ /**
+ * The callback interface used by {@link SwipeDismissTouchListener} to inform its client
+ * about a successful dismissal of the view for which it was created.
+ */
+ public interface DismissCallbacks {
+ /**
+ * Called to determine whether the view can be dismissed.
+ */
+ boolean canDismiss(Object token);
+
+ /**
+ * Called when the user has indicated they she would like to dismiss the view.
+ *
+ * @param view The originating {@link View} to be dismissed.
+ * @param token The optional token passed to this object's constructor.
+ */
+ void onDismiss(View view, Object token);
+ }
+
+ /**
+ * Constructs a new swipe-to-dismiss touch listener for the given view.
+ *
+ * @param view The view to make dismissable.
+ * @param token An optional token/cookie object to be passed through to the callback.
+ * @param callbacks The callback to trigger when the user has indicated that she would like to
+ * dismiss this view.
+ */
+ public SwipeDismissTouchListener(View view, Object token, DismissCallbacks callbacks) {
+ ViewConfiguration vc = ViewConfiguration.get(view.getContext());
+ mSlop = vc.getScaledTouchSlop();
+ mMinFlingVelocity = vc.getScaledMinimumFlingVelocity() * 16;
+ mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity();
+ mAnimationTime = view.getContext().getResources().getInteger(
+ android.R.integer.config_shortAnimTime);
+ mView = view;
+ mToken = token;
+ mCallbacks = callbacks;
+ }
+
+ @Override
+ public boolean onTouch(View view, MotionEvent motionEvent) {
+ // offset because the view is translated during swipe
+ motionEvent.offsetLocation(mTranslationX, 0);
+
+ if (mViewWidth < 2) {
+ mViewWidth = mView.getWidth();
+ }
+
+ switch (motionEvent.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN: {
+ // TODO: ensure this is a finger, and set a flag
+ mDownX = motionEvent.getRawX();
+ mDownY = motionEvent.getRawY();
+ if (mCallbacks.canDismiss(mToken)) {
+ mVelocityTracker = VelocityTracker.obtain();
+ mVelocityTracker.addMovement(motionEvent);
+ }
+ view.onTouchEvent(motionEvent);
+ return true;
+ }
+
+ case MotionEvent.ACTION_UP: {
+ if (mVelocityTracker == null) {
+ break;
+ }
+
+ float deltaX = motionEvent.getRawX() - mDownX;
+ mVelocityTracker.addMovement(motionEvent);
+ mVelocityTracker.computeCurrentVelocity(1000);
+ float velocityX = mVelocityTracker.getXVelocity();
+ float absVelocityX = Math.abs(velocityX);
+ float absVelocityY = Math.abs(mVelocityTracker.getYVelocity());
+ boolean dismiss = false;
+ boolean dismissRight = false;
+ if (Math.abs(deltaX) > mViewWidth / 2 && mSwiping) {
+ dismiss = true;
+ dismissRight = deltaX > 0;
+ } else if (mMinFlingVelocity <= absVelocityX && absVelocityX <= mMaxFlingVelocity
+ && absVelocityY < absVelocityX
+ && mSwiping) {
+ // dismiss only if flinging in the same direction as dragging
+ dismiss = (velocityX < 0) == (deltaX < 0);
+ dismissRight = mVelocityTracker.getXVelocity() > 0;
+ }
+ if (dismiss) {
+ // dismiss
+ mView.animate()
+ .translationX(dismissRight ? mViewWidth : -mViewWidth)
+ .alpha(0)
+ .setDuration(mAnimationTime)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ performDismiss();
+ }
+ });
+ } else if (mSwiping) {
+ // cancel
+ mView.animate()
+ .translationX(0)
+ .alpha(1)
+ .setDuration(mAnimationTime)
+ .setListener(null);
+ }
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ mTranslationX = 0;
+ mDownX = 0;
+ mDownY = 0;
+ mSwiping = false;
+ break;
+ }
+
+ case MotionEvent.ACTION_CANCEL: {
+ if (mVelocityTracker == null) {
+ break;
+ }
+
+ mView.animate()
+ .translationX(0)
+ .alpha(1)
+ .setDuration(mAnimationTime)
+ .setListener(null);
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ mTranslationX = 0;
+ mDownX = 0;
+ mDownY = 0;
+ mSwiping = false;
+ break;
+ }
+
+ case MotionEvent.ACTION_MOVE: {
+ if (mVelocityTracker == null) {
+ break;
+ }
+
+ mVelocityTracker.addMovement(motionEvent);
+ float deltaX = motionEvent.getRawX() - mDownX;
+ float deltaY = motionEvent.getRawY() - mDownY;
+ if (Math.abs(deltaX) > mSlop && Math.abs(deltaY) < Math.abs(deltaX) / 2) {
+ mSwiping = true;
+ mSwipingSlop = (deltaX > 0 ? mSlop : -mSlop);
+ mView.getParent().requestDisallowInterceptTouchEvent(true);
+
+ // Cancel listview's touch
+ MotionEvent cancelEvent = MotionEvent.obtain(motionEvent);
+ cancelEvent.setAction(MotionEvent.ACTION_CANCEL |
+ (motionEvent.getActionIndex() <<
+ MotionEvent.ACTION_POINTER_INDEX_SHIFT));
+ mView.onTouchEvent(cancelEvent);
+ cancelEvent.recycle();
+ }
+
+ if (mSwiping) {
+ mTranslationX = deltaX;
+ mView.setTranslationX(deltaX - mSwipingSlop);
+ // TODO: use an ease-out interpolator or such
+ mView.setAlpha(Math.max(0f, Math.min(1f,
+ 1f - 2f * Math.abs(deltaX) / mViewWidth)));
+ return true;
+ }
+ break;
+ }
+ }
+ return false;
+ }
+
+ private void performDismiss() {
+ // Animate the dismissed view to zero-height and then fire the dismiss callback.
+ // This triggers layout on each animation frame; in the future we may want to do something
+ // smarter and more performant.
+
+ final ViewGroup.LayoutParams lp = mView.getLayoutParams();
+ final int originalHeight = mView.getHeight();
+
+ ValueAnimator animator = ValueAnimator.ofInt(originalHeight, 1).setDuration(mAnimationTime);
+
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mCallbacks.onDismiss(mView, mToken);
+ // Reset view presentation
+ mView.setAlpha(1f);
+ mView.setTranslationX(0);
+ lp.height = originalHeight;
+ mView.setLayoutParams(lp);
+ }
+ });
+
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator valueAnimator) {
+ lp.height = (Integer) valueAnimator.getAnimatedValue();
+ mView.setLayoutParams(lp);
+ }
+ });
+
+ animator.start();
+ }
+} \ No newline at end of file
diff --git a/src/com/android/cards/view/listener/SwipeDismissViewTouchListener.java b/src/it/gmariotti/cardslib/library/view/listener/SwipeDismissViewTouchListener.java
index 16fb6ec..2768a25 100644
--- a/src/com/android/cards/view/listener/SwipeDismissViewTouchListener.java
+++ b/src/it/gmariotti/cardslib/library/view/listener/SwipeDismissViewTouchListener.java
@@ -28,8 +28,10 @@ import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
+import com.android.cards.R;
import com.android.cards.internal.Card;
-import com.android.cards.view.CardView;
+import com.android.cards.view.base.CardViewWrapper;
+
/**
* It is based on Roman Nurik code.
@@ -51,18 +53,22 @@ public class SwipeDismissViewTouchListener implements View.OnTouchListener {
private long mAnimationTime;
// Fixed properties
- private CardView mCardView;
+ private CardViewWrapper mCardView;
private DismissCallbacks mCallbacks;
private int mViewWidth = 1; // 1 and not 0 to prevent dividing by zero
// Transient properties
private float mDownX;
+ private float mDownY;
private Card mToken;
private boolean mSwiping;
+ private int mSwipingSlop;
private VelocityTracker mVelocityTracker;
private boolean mPaused;
private float mTranslationX;
+ private int swipeDistanceDivisor = 2;
+
/**
* The callback interface used by {@link SwipeDismissViewTouchListener}
* to inform its client about a successful dismissal of the view for which it was created.
@@ -79,7 +85,7 @@ public class SwipeDismissViewTouchListener implements View.OnTouchListener {
* @param cardView The originating {@link com.android.cards.view.CardView}.
* @parma card Card
*/
- void onDismiss(CardView cardView,Card card);
+ void onDismiss(CardViewWrapper cardView,Card card);
}
/**
@@ -88,7 +94,7 @@ public class SwipeDismissViewTouchListener implements View.OnTouchListener {
* @param cardView The card view which should be dismissable.
* @param callbacks The callback to trigger when the user has indicated that she
*/
- public SwipeDismissViewTouchListener(CardView cardView,
+ public SwipeDismissViewTouchListener(CardViewWrapper cardView,
Card card,
DismissCallbacks callbacks) {
ViewConfiguration vc = ViewConfiguration.get(cardView.getContext());
@@ -100,6 +106,7 @@ public class SwipeDismissViewTouchListener implements View.OnTouchListener {
mCardView = cardView;
mToken= card;
mCallbacks = callbacks;
+ swipeDistanceDivisor = cardView.getContext().getResources().getInteger(R.integer.list_card_swipe_distance_divisor);
}
/**
@@ -119,7 +126,7 @@ public class SwipeDismissViewTouchListener implements View.OnTouchListener {
motionEvent.offsetLocation(mTranslationX, 0);
if (mViewWidth < 2) {
- mViewWidth = mCardView.getWidth();
+ mViewWidth = ((View)mCardView).getWidth();
}
switch (motionEvent.getActionMasked()) {
@@ -131,6 +138,7 @@ public class SwipeDismissViewTouchListener implements View.OnTouchListener {
// TODO: ensure this is a finger, and set a flag
mDownX = motionEvent.getRawX();
+ mDownY = motionEvent.getRawY();
if (mCallbacks.canDismiss(mToken)) {
mVelocityTracker = VelocityTracker.obtain();
mVelocityTracker.addMovement(motionEvent);
@@ -153,12 +161,12 @@ public class SwipeDismissViewTouchListener implements View.OnTouchListener {
float absVelocityY = Math.abs(mVelocityTracker.getYVelocity());
boolean dismiss = false;
boolean dismissRight = false;
- if (Math.abs(deltaX) > mViewWidth / 2) {
+ if (Math.abs(deltaX) > mViewWidth / swipeDistanceDivisor && mSwiping) {
dismiss = true;
dismissRight = deltaX > 0;
} else if (mMinFlingVelocity <= absVelocityX
&& absVelocityX <= mMaxFlingVelocity
- && absVelocityY < absVelocityX) {
+ && absVelocityY < absVelocityX && mSwiping) {
// dismiss only if flinging in the same direction as dragging
dismiss = (velocityX < 0) == (deltaX < 0);
dismissRight = mVelocityTracker.getXVelocity() > 0;
@@ -166,7 +174,7 @@ public class SwipeDismissViewTouchListener implements View.OnTouchListener {
if (dismiss) {
// dismiss
- mCardView.animate()
+ ((View)mCardView).animate()
.translationX(dismissRight ? mViewWidth : -mViewWidth)
.alpha(0).setDuration(mAnimationTime)
.setListener(new AnimatorListenerAdapter() {
@@ -175,14 +183,35 @@ public class SwipeDismissViewTouchListener implements View.OnTouchListener {
performDismiss();
}
});
- } else {
+ } else if (mSwiping) {
// cancel
- mCardView.animate().translationX(0).alpha(1)
+ ((View)mCardView).animate().translationX(0).alpha(1)
.setDuration(mAnimationTime).setListener(null);
}
mVelocityTracker.recycle();
mVelocityTracker = null;
+ mTranslationX = 0;
+ mDownX = 0;
+ mDownY = 0;
+ mSwiping = false;
+ break;
+ }
+
+ case MotionEvent.ACTION_CANCEL: {
+ if (mVelocityTracker == null) {
+ break;
+ }
+
+ ((View)mCardView).animate()
+ .translationX(0)
+ .alpha(1)
+ .setDuration(mAnimationTime)
+ .setListener(null);
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ mTranslationX = 0;
mDownX = 0;
+ mDownY = 0;
mSwiping = false;
break;
}
@@ -194,23 +223,26 @@ public class SwipeDismissViewTouchListener implements View.OnTouchListener {
mVelocityTracker.addMovement(motionEvent);
float deltaX = motionEvent.getRawX() - mDownX;
- if (Math.abs(deltaX) > mSlop) {
+ float deltaY = motionEvent.getRawY() - mDownY;
+ if (Math.abs(deltaX) > mSlop && Math.abs(deltaY) < Math.abs(deltaX) / 2) {
mSwiping = true;
- mCardView.getParent().requestDisallowInterceptTouchEvent(true);
-
+ ((View)mCardView).getParent().requestDisallowInterceptTouchEvent(true);
+ mSwipingSlop = (deltaX > 0 ? mSlop : -mSlop);
+
// Cancel ListView's touch (un-highlighting the item)
MotionEvent cancelEvent = MotionEvent.obtain(motionEvent);
cancelEvent
.setAction(MotionEvent.ACTION_CANCEL
| (motionEvent.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT));
- mCardView.onTouchEvent(cancelEvent);
+ ((View)mCardView).onTouchEvent(cancelEvent);
cancelEvent.recycle();
}
if (mSwiping) {
mTranslationX = deltaX;
- mCardView.setTranslationX(deltaX);
- mCardView.setAlpha(Math.max(0f,
+ //((View)mCardView).setTranslationX(deltaX);
+ ((View)mCardView).setTranslationX(deltaX - mSwipingSlop);
+ ((View)mCardView).setAlpha(Math.max(0f,
Math.min(1f, 1f - 2f * Math.abs(deltaX) / mViewWidth)));
return true;
}
@@ -226,8 +258,8 @@ public class SwipeDismissViewTouchListener implements View.OnTouchListener {
// This triggers layout on each animation frame; in the future we may want to do something
// smarter and more performant.
- final ViewGroup.LayoutParams lp = mCardView.getLayoutParams();
- final int originalHeight = mCardView.getHeight();
+ final ViewGroup.LayoutParams lp = ((View)mCardView).getLayoutParams();
+ final int originalHeight = ((View)mCardView).getHeight();
ValueAnimator animator = ValueAnimator.ofInt(originalHeight, 1)
.setDuration(mAnimationTime);
@@ -238,11 +270,11 @@ public class SwipeDismissViewTouchListener implements View.OnTouchListener {
mCallbacks.onDismiss(mCardView,mToken);
// Reset view presentation
- mCardView.setAlpha(1f);
- mCardView.setTranslationX(0);
+ ((View)mCardView).setAlpha(1f);
+ ((View)mCardView).setTranslationX(0);
//ViewGroup.LayoutParams lp = mCardView.getLayoutParams();
lp.height = originalHeight;
- mCardView.setLayoutParams(lp);
+ ((View) mCardView).setLayoutParams(lp);
}
});
@@ -250,10 +282,10 @@ public class SwipeDismissViewTouchListener implements View.OnTouchListener {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
lp.height = (Integer) valueAnimator.getAnimatedValue();
- mCardView.setLayoutParams(lp);
+ ((View)mCardView).setLayoutParams(lp);
}
});
animator.start();
}
-}
+} \ No newline at end of file
diff --git a/src/com/android/cards/view/listener/SwipeOnScrollListener.java b/src/it/gmariotti/cardslib/library/view/listener/SwipeOnScrollListener.java
index efcc193..be37336 100644
--- a/src/com/android/cards/view/listener/SwipeOnScrollListener.java
+++ b/src/it/gmariotti/cardslib/library/view/listener/SwipeOnScrollListener.java
@@ -48,4 +48,4 @@ public class SwipeOnScrollListener implements AbsListView.OnScrollListener {
@Override
public void onScroll(final AbsListView view, final int firstVisibleItem, final int visibleItemCount, final int totalItemCount) {
}
-}
+} \ No newline at end of file
diff --git a/src/it/gmariotti/cardslib/library/view/listener/UndoBarController.java b/src/it/gmariotti/cardslib/library/view/listener/UndoBarController.java
new file mode 100644
index 0000000..4513c8a
--- /dev/null
+++ b/src/it/gmariotti/cardslib/library/view/listener/UndoBarController.java
@@ -0,0 +1,478 @@
+/*
+ * ******************************************************************************
+ * Copyright (c) 2013 Roman Nurik, 2013-2014 Gabriele Mariotti.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * *****************************************************************************
+ */
+
+package com.android.cards.view.listener;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.ViewPropertyAnimator;
+import android.widget.TextView;
+
+import com.android.cards.R;
+import com.android.cards.internal.CardArrayAdapter;
+
+/**
+ * It is based on Roman Nurik code.
+ * See this link for original code:
+ * https://code.google.com/p/romannurik-code/source/browse/#git%2Fmisc%2Fundobar
+ *
+ *
+ */
+public class UndoBarController {
+
+ private View mBarView;
+ private TextView mMessageView;
+ private ViewPropertyAnimator mBarAnimator;
+ private Handler mHideHandler = new Handler();
+
+ private UndoListener mUndoListener;
+ private UndoBarHideListener mUndoBarHideListener;
+
+ // State objects
+ private Parcelable mUndoToken;
+ private CharSequence mUndoMessage;
+
+ private UndoBarUIElements mUndoBarUIElements;
+
+ /**
+ * Interface to listen the undo controller actions
+ */
+ public interface UndoListener {
+ /*
+ * Called when you undo the action
+ */
+ void onUndo(Parcelable undoToken);
+ }
+
+ /**
+ * Interface to listen for when the Undo controller hides the Undo Bar,
+ * after it times out from being shown for the currently dismissed mUndoToken.
+ */
+ public interface UndoBarHideListener {
+ /**
+ * Called when the UndoBar is hidden after being shown.
+ * @param undoOccurred true if the user pressed the undo button
+ * for the current mUndoToken.
+ */
+ void onUndoBarHide(boolean undoOccurred);
+ }
+
+ public UndoBarController(View undoBarView, UndoListener undoListener) {
+ this (undoBarView,undoListener,null);
+ }
+
+ public UndoBarController(View undoBarView, UndoListener undoListener,UndoBarUIElements undoBarUIElements) {
+ mBarView = undoBarView;
+ mBarAnimator = mBarView.animate();
+ mUndoListener = undoListener;
+
+ if (undoBarUIElements==null)
+ undoBarUIElements = new DefaultUndoBarUIElements();
+ mUndoBarUIElements = undoBarUIElements;
+
+ mMessageView = (TextView) mBarView.findViewById(mUndoBarUIElements.getUndoBarMessageId());
+ mBarView.findViewById(mUndoBarUIElements.getUndoBarButtonId())
+ .setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ hideUndoBar(false);
+ mUndoListener.onUndo(mUndoToken);
+ // Remove the reference to the undo token, since the undo has occurred.
+ mUndoToken = null;
+ }
+ });
+
+ setupAnimation();
+
+ if (mUndoBarUIElements.isEnabledUndoBarSwipeAction() != UndoBarUIElements.SwipeDirectionEnabled.NONE){
+ setupSwipeActionOnUndoBar();
+ }
+
+ hideUndoBar(true);
+ }
+
+
+
+ public void showUndoBar(boolean immediate, CharSequence message,
+ Parcelable undoToken, UndoBarHideListener undoBarHideListener) {
+
+ // We're replacing the existing UndoBarHideListener, meaning that
+ // the original object removal was not undone. So, execute
+ // onUndoBarHide for the previous listener.
+ if (mUndoBarHideListener != null) {
+ mUndoBarHideListener.onUndoBarHide(mUndoToken == null);
+ }
+
+
+ mUndoToken = undoToken;
+ mUndoMessage = message;
+ mUndoBarHideListener = undoBarHideListener;
+ mMessageView.setText(mUndoMessage);
+
+ mHideHandler.removeCallbacks(mHideRunnable);
+ mHideHandler.postDelayed(mHideRunnable,
+ mBarView.getResources().getInteger(R.integer.list_card_undobar_hide_delay));
+
+ mBarView.setVisibility(View.VISIBLE);
+ if (immediate) {
+ mBarView.setAlpha(1);
+ } else {
+
+ if (mUndoBarUIElements.getAnimationType() == UndoBarUIElements.AnimationType.ALPHA) {
+
+ mBarAnimator.cancel();
+ mBarAnimator
+ .alpha(1)
+ .setDuration(
+ mBarView.getResources()
+ .getInteger(android.R.integer.config_shortAnimTime))
+ .setListener(null);
+ } else if (mUndoBarUIElements.getAnimationType() == UndoBarUIElements.AnimationType.TOPBOTTOM){
+
+ mBarAnimator.cancel();
+ mBarAnimator
+ .alpha(1)
+ .translationY(0)
+ .setDuration(
+ mBarView.getResources()
+ .getInteger(android.R.integer.config_mediumAnimTime))
+ .setListener(null);
+
+ }
+ }
+ }
+
+ public void hideUndoBar(boolean immediate) {
+ mHideHandler.removeCallbacks(mHideRunnable);
+ if (immediate) {
+ mBarView.setVisibility(View.GONE);
+ mBarView.setAlpha(0);
+ mUndoMessage = null;
+ if (mUndoBarHideListener != null) {
+ // The undo has occurred only if mUndoToken was set to null.
+ mUndoBarHideListener.onUndoBarHide(mUndoToken == null);
+ }
+ mUndoBarHideListener = null;
+ mUndoToken = null;
+ } else {
+ mBarAnimator.cancel();
+
+ if (mUndoBarUIElements.getAnimationType() == UndoBarUIElements.AnimationType.ALPHA) {
+ mBarAnimator
+ .alpha(0)
+ .setDuration(mBarView.getResources()
+ .getInteger(android.R.integer.config_shortAnimTime))
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mBarView.setVisibility(View.GONE);
+ mUndoMessage = null;
+ if (mUndoBarHideListener != null) {
+ // The undo has occurred only if mUndoToken was set to null.
+ mUndoBarHideListener.onUndoBarHide(mUndoToken == null);
+ }
+ mUndoBarHideListener = null;
+ mUndoToken = null;
+ }
+ });
+ } else if (mUndoBarUIElements.getAnimationType() == UndoBarUIElements.AnimationType.TOPBOTTOM){
+ mBarAnimator
+ .alpha(0)
+ .translationY(+mBarView.getHeight())
+ .setDuration(mBarView.getResources()
+ .getInteger(android.R.integer.config_shortAnimTime))
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mBarView.setVisibility(View.GONE);
+ mUndoMessage = null;
+ if (mUndoBarHideListener != null) {
+ // The undo has occurred only if mUndoToken was set to null.
+ mUndoBarHideListener.onUndoBarHide(mUndoToken == null);
+ }
+ mUndoBarHideListener = null;
+ mUndoToken = null;
+ }
+ });
+ }
+ }
+ }
+
+ public void onSaveInstanceState(Bundle outState) {
+ outState.putCharSequence("undo_message", mUndoMessage);
+ outState.putParcelable("undo_token", mUndoToken);
+ }
+
+ public void onRestoreInstanceState(Bundle savedInstanceState) {
+ if (savedInstanceState != null) {
+ mUndoMessage = savedInstanceState.getCharSequence("undo_message");
+ mUndoToken = savedInstanceState.getParcelable("undo_token");
+
+ if (mUndoToken != null || !TextUtils.isEmpty(mUndoMessage)) {
+ showUndoBar(true, mUndoMessage, mUndoToken, mUndoBarHideListener);
+ }
+ }
+ }
+
+ private Runnable mHideRunnable = new Runnable() {
+ @Override
+ public void run() {
+ hideUndoBar(false);
+ }
+ };
+
+ public Parcelable getUndoToken(){
+ return mUndoToken;
+ }
+
+ private void setupAnimation(){
+ if (mUndoBarUIElements.getAnimationType() == UndoBarUIElements.AnimationType.TOPBOTTOM) {
+ mBarView.setTranslationY(mBarView.getHeight());
+ }
+ }
+
+ private void setupSwipeActionOnUndoBar() {
+ if (mBarView != null) {
+
+ if (mUndoBarUIElements.isEnabledUndoBarSwipeAction() == UndoBarUIElements.SwipeDirectionEnabled.LEFTRIGHT) {
+
+ mBarView.setOnTouchListener(new SwipeDismissTouchListener(mBarView, null,
+ new SwipeDismissTouchListener.DismissCallbacks() {
+ @Override
+ public boolean canDismiss(Object token) {
+ return mUndoBarUIElements.isEnabledUndoBarSwipeAction() != UndoBarUIElements.SwipeDirectionEnabled.NONE;
+ }
+
+ @Override
+ public void onDismiss(View view, Object token) {
+ hideUndoBar(true);
+ mUndoListener.onUndo(mUndoToken);
+ // Remove the reference to the undo token, since the undo has occurred.
+ mUndoToken = null;
+ }
+ }));
+ } else if (mUndoBarUIElements.isEnabledUndoBarSwipeAction() == UndoBarUIElements.SwipeDirectionEnabled.TOPBOTTOM) {
+
+ mBarView.setOnTouchListener(new SwipeDismissTopBottomTouchListener(mBarView, null,
+ new SwipeDismissTopBottomTouchListener.DismissCallbacks() {
+ @Override
+ public boolean canDismiss(Object token) {
+ return mUndoBarUIElements.isEnabledUndoBarSwipeAction() != UndoBarUIElements.SwipeDirectionEnabled.NONE;
+ }
+
+ @Override
+ public void onDismiss(View view, Object token) {
+ hideUndoBar(true);
+ mUndoListener.onUndo(mUndoToken);
+ // Remove the reference to the undo token, since the undo has occurred.
+ mUndoToken = null;
+ }
+ }));
+ }
+ }
+
+ }
+
+ // -------------------------------------------------------------
+ // Undo Custom Bar
+ // -------------------------------------------------------------
+
+ /**
+ * Interface to set the ui elements in undo bar
+ */
+ public interface UndoBarUIElements{
+
+ /**
+ * UndoBar id
+ * @return
+ */
+ public int getUndoBarId();
+
+ /**
+ * TextView Id which displays message
+ *
+ * @return
+ */
+ public int getUndoBarMessageId();
+
+ /**
+ * UndoButton Id
+ *
+ * @return
+ */
+ public int getUndoBarButtonId();
+
+ /**
+ * UndoMessage.
+ * Implement this method to customize the undo message dynamically.
+ * </p>
+ * You can't find the cards with these positions in your arrayAdapter because the cards are removed.
+ * You have to/can use your id itemIds, to identify your cards.
+ *
+ * @param cardArrayAdapter array Adapter
+ * @param itemIds ids of items
+ * @param itemPositions position of removed items
+ * @return
+ */
+ public String getMessageUndo(CardArrayAdapter cardArrayAdapter,String[] itemIds,int[] itemPositions);
+
+ /**
+ * Define the swipe action to remove the undobar.
+ * @return
+ */
+ public SwipeDirectionEnabled isEnabledUndoBarSwipeAction();
+
+ /**
+ * Define the animation type for the undobar when it appears.
+ * @return
+ */
+ public AnimationType getAnimationType();
+
+
+ /**
+ * Enum to define the animation type of the undobar.<p/>
+ * Use the {@link AnimationType#ALPHA} for an alpha animation, or {@link AnimationType#TOPBOTTOM} for a translation from bottom to top.
+ */
+ public enum AnimationType {
+ ALPHA(0),
+ TOPBOTTOM(1);
+
+ private final int mValue;
+
+ private AnimationType(int value) {
+ mValue = value;
+ }
+
+ public int getValue() {
+ return mValue;
+ }
+ }
+
+ /**
+ * Enum to define the direction of the swipe action.
+ * <p/>
+ * You can use {@link SwipeDirectionEnabled#NONE} to disable the swipe action or {@link SwipeDirectionEnabled#LEFTRIGHT} to enable an action in left-right direction
+ * or {@link SwipeDirectionEnabled#TOPBOTTOM} to define a swipe action from top to bottom.
+ */
+ public enum SwipeDirectionEnabled {
+ NONE(0),
+ LEFTRIGHT(1),
+ TOPBOTTOM(2);
+
+ private final int mValue;
+
+ private SwipeDirectionEnabled(int value) {
+ mValue = value;
+ }
+
+ public int getValue() {
+ return mValue;
+ }
+ }
+
+ }
+
+ /**
+ * Default UndoBar
+ *
+ * You can provide a custom UndoBar.
+ * This UndoBar has to contains these elements:
+ * <ul>
+ * <li>A TextView</li>
+ * <li>A Button</li>
+ * <li>A root element with an id attribute </li>
+ * </ul>
+ *
+ * You should use the same Ids provided in the default layout list_card_undo_message,
+ * but if you have to use different ids you can use the CardArrayAdapter.setUndoBarUIElements.
+ *
+ * Example:
+ * <code>
+ * mCardArrayAdapter.setUndoBarUIElements(new UndoBarController.DefaultUndoBarUIElements(){
+ *
+ * //Override methods to customize the elements
+ * }
+ * </code>
+ * It is very important to set the UndoBarUIElements before to call the setEnableUndo(true);
+ *
+ */
+ public static class DefaultUndoBarUIElements implements UndoBarUIElements {
+
+ public DefaultUndoBarUIElements(){};
+
+ @Override
+ public int getUndoBarId() {
+ return R.id.list_card_undobar;
+ }
+
+ @Override
+ public int getUndoBarMessageId() {
+ return R.id.list_card_undobar_message;
+ }
+
+ @Override
+ public int getUndoBarButtonId() {
+ return R.id.list_card_undobar_button;
+ }
+
+ @Override
+ public String getMessageUndo(CardArrayAdapter cardArrayAdapter, String[] itemIds, int[] itemPositions) {
+ if (cardArrayAdapter!=null && cardArrayAdapter.getContext()!=null) {
+ Resources res = cardArrayAdapter.getContext().getResources();
+ if (res!=null)
+ return res.getQuantityString(R.plurals.list_card_undo_items, itemPositions.length, itemPositions.length);
+ }
+ return null;
+ }
+
+ @Override
+ public SwipeDirectionEnabled isEnabledUndoBarSwipeAction() {
+ return SwipeDirectionEnabled.NONE;
+ }
+
+ @Override
+ public AnimationType getAnimationType() {
+ return AnimationType.ALPHA;
+ }
+
+ };
+
+
+ /**
+ * Sets UndoBar UI Elements
+ *
+ * @return
+ */
+ public UndoBarUIElements getUndoBarUIElements() {
+ return mUndoBarUIElements;
+ }
+
+ /**
+ * Returns UndoBar UI Elements
+ * @param undoBarUIElements
+ */
+ public void setUndoBarUIElements(UndoBarUIElements undoBarUIElements) {
+ this.mUndoBarUIElements = undoBarUIElements;
+ }
+}
diff --git a/src/com/android/cards/view/listener/UndoCard.java b/src/it/gmariotti/cardslib/library/view/listener/UndoCard.java
index 10f8b3a..10f8b3a 100644
--- a/src/com/android/cards/view/listener/UndoCard.java
+++ b/src/it/gmariotti/cardslib/library/view/listener/UndoCard.java
diff --git a/src/it/gmariotti/cardslib/library/view/listener/dismiss/AbstractDismissableManager.java b/src/it/gmariotti/cardslib/library/view/listener/dismiss/AbstractDismissableManager.java
new file mode 100644
index 0000000..7d8f4eb
--- /dev/null
+++ b/src/it/gmariotti/cardslib/library/view/listener/dismiss/AbstractDismissableManager.java
@@ -0,0 +1,44 @@
+/*
+ * ******************************************************************************
+ * Copyright (c) 2013-2014 Gabriele Mariotti.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * *****************************************************************************
+ */
+
+package com.android.cards.view.listener.dismiss;
+
+import android.widget.Adapter;
+
+import com.android.cards.internal.Card;
+
+/**
+ * @author Gabriele Mariotti (gabri.mariotti@gmail.com)
+ */
+public abstract class AbstractDismissableManager implements Dismissable {
+
+ protected Adapter mAdapter;
+
+ @Override
+ public final boolean isDismissable(int position, Card card) {
+ return card.isSwipeable();
+ }
+
+ @Override
+ public abstract SwipeDirection getSwipeDirectionAllowed();
+
+
+ public void setAdapter(Adapter adapter) {
+ mAdapter = adapter;
+ }
+}
diff --git a/src/it/gmariotti/cardslib/library/view/listener/dismiss/DefaultDismissableManager.java b/src/it/gmariotti/cardslib/library/view/listener/dismiss/DefaultDismissableManager.java
new file mode 100644
index 0000000..3a07b02
--- /dev/null
+++ b/src/it/gmariotti/cardslib/library/view/listener/dismiss/DefaultDismissableManager.java
@@ -0,0 +1,35 @@
+/*
+ * ******************************************************************************
+ * Copyright (c) 2013-2014 Gabriele Mariotti.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * *****************************************************************************
+ */
+
+package com.android.cards.view.listener.dismiss;
+
+/**
+ * Default DismissableManager.<p/>
+ * Extend this class to implement you favorite logic.
+ *
+ * @author Gabriele Mariotti (gabri.mariotti@gmail.com)
+ */
+public class DefaultDismissableManager extends AbstractDismissableManager {
+
+
+ @Override
+ public SwipeDirection getSwipeDirectionAllowed() {
+ return SwipeDirection.BOTH;
+ }
+
+}
diff --git a/src/it/gmariotti/cardslib/library/view/listener/dismiss/Dismissable.java b/src/it/gmariotti/cardslib/library/view/listener/dismiss/Dismissable.java
new file mode 100644
index 0000000..1b5bfe9
--- /dev/null
+++ b/src/it/gmariotti/cardslib/library/view/listener/dismiss/Dismissable.java
@@ -0,0 +1,59 @@
+/*
+ * ******************************************************************************
+ * Copyright (c) 2013-2014 Gabriele Mariotti.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * *****************************************************************************
+ */
+
+package com.android.cards.view.listener.dismiss;
+
+import android.widget.Adapter;
+
+import com.android.cards.internal.Card;
+
+/**
+ * An interface to specify if items can or cannot be dismissed and the SwipeDirection
+ * @author Gabriele Mariotti (gabri.mariotti@gmail.com)
+ */
+public interface Dismissable {
+
+ /**
+ * Returns whether the item for given id and position can be dismissed.
+ * @param position the position of the item.
+ * @param card card
+ * @return true if the item can be dismissed, false otherwise.
+ */
+ boolean isDismissable(int position, Card card);
+
+ SwipeDirection getSwipeDirectionAllowed();
+
+ void setAdapter(Adapter adapter);
+
+
+ public enum SwipeDirection {
+ BOTH(0),
+ LEFT(1),
+ RIGHT(2);
+
+ private final int mValue;
+
+ private SwipeDirection(int value) {
+ mValue = value;
+ }
+
+ public int getValue() {
+ return mValue;
+ }
+ }
+}