From 22db727dbf1d04fe001659a361778ad540ffd4af Mon Sep 17 00:00:00 2001 From: Floens Date: Mon, 18 May 2015 00:59:30 +0200 Subject: [PATCH] Remove old classes and xml files Removing all old activities/fragments/views that are not used in the new UI system. Make all icons material. Make lint happy(ier) Add license headers where missing. --- Clover/app/src/main/AndroidManifest.xml | 59 +- .../android/dslv/DragSortController.java | 469 --- .../android/dslv/DragSortCursorAdapter.java | 239 -- .../mobeta/android/dslv/DragSortItemView.java | 92 - .../dslv/DragSortItemViewCheckable.java | 46 - .../mobeta/android/dslv/DragSortListView.java | 2974 ----------------- .../dslv/ResourceDragSortCursorAdapter.java | 155 - .../dslv/SimpleDragSortCursorAdapter.java | 448 --- .../android/dslv/SimpleFloatViewManager.java | 87 - .../src/main/java/org/floens/chan/Chan.java | 220 ++ .../java/org/floens/chan/ChanApplication.java | 204 +- .../org/floens/chan/chan/ImageSearch.java | 6 +- .../chan/controller/ControllerLogic.java | 17 + .../chan/controller/FadeInTransition.java | 17 + .../chan/controller/FadeOutTransition.java | 17 + .../chan/{utils => core/cache}/FileCache.java | 9 +- .../floens/chan/core/loader/ChanLoader.java | 62 +- .../floens/chan/core/loader/ChanParser.java | 12 +- .../chan/core/loader/EndOfLineException.java | 37 - .../chan/core/manager/BoardManager.java | 10 +- .../chan/core/manager/ThreadManager.java | 604 ---- .../chan/core/manager/WatchManager.java | 26 +- .../org/floens/chan/core/model/Loadable.java | 40 +- .../java/org/floens/chan/core/model/Post.java | 6 +- .../org/floens/chan/core/model/PostImage.java | 17 + .../chan/core/net/ByteArrayRequest.java | 47 - .../chan/core/net/ChanReaderRequest.java | 50 +- .../org/floens/chan/core/net/FileRequest.java | 58 - .../chan/core/net/JsonReaderRequest.java | 11 +- .../core/presenter/ImageViewerPresenter.java | 17 + .../chan/core/presenter/ReplyPresenter.java | 31 +- .../chan/core/presenter/ThreadPresenter.java | 8 +- .../org/floens/chan/core/reply/HttpCall.java | 17 + .../floens/chan/core/reply/ReplyHttpCall.java | 17 + .../floens/chan/core/reply/ReplyManager.java | 189 +- .../chan/core/settings/BooleanSetting.java | 17 + .../chan/core/settings/ChanSettings.java | 201 +- .../floens/chan/core/settings/Setting.java | 17 + .../chan/core/settings/StringSetting.java | 17 + .../floens/chan/core/watch/PinWatcher.java | 6 +- .../org/floens/chan/test/TestActivity.java | 6 +- .../org/floens/chan/ui/ThemeActivity.java | 48 - .../chan/ui/activity/AboutActivity.java | 41 - .../ui/activity/AdvancedSettingsActivity.java | 134 - .../floens/chan/ui/activity/BaseActivity.java | 384 --- .../floens/chan/ui/activity/BoardEditor.java | 451 --- .../floens/chan/ui/activity/ChanActivity.java | 759 ----- .../chan/ui/activity/DeveloperActivity.java | 109 - .../chan/ui/activity/ImagePickActivity.java | 4 +- .../chan/ui/activity/ImageViewActivity.java | 271 -- .../chan/ui/activity/LicenseActivity.java | 38 - .../ui/activity/PassSettingsActivity.java | 188 -- .../chan/ui/activity/ReplyActivity.java | 81 - .../chan/ui/activity/SettingsActivity.java | 90 - .../chan/ui/activity/StartActivity.java | 25 +- .../ui/activity/WatchSettingsActivity.java | 198 -- .../chan/ui/adapter/ImageViewAdapter.java | 67 - .../chan/ui/adapter/ImageViewerAdapter.java | 17 + .../floens/chan/ui/adapter/PinAdapter.java | 36 +- .../floens/chan/ui/adapter/PinnedAdapter.java | 231 -- .../chan/ui/animation/ScrollerRunnable.java | 140 - .../SwipeDismissListViewTouchListener.java | 409 --- .../ui/animation/ViewFlipperAnimations.java | 55 - .../org/floens/chan/ui/cell/PostCell.java | 36 +- .../floens/chan/ui/cell/ThreadStatusCell.java | 19 +- .../AdvancedSettingsController.java | 24 +- .../ui/controller/BoardEditController.java | 23 +- .../chan/ui/controller/BrowseController.java | 12 +- .../DeveloperSettingsController.java | 27 +- .../ui/controller/ImageViewerController.java | 25 +- .../ImageViewerNavigationController.java | 17 + .../ui/controller/LicensesController.java | 17 + .../ui/controller/PassSettingsController.java | 21 +- .../ui/controller/PostRepliesController.java | 35 +- .../controller/RootNavigationController.java | 6 +- .../chan/ui/controller/ThreadController.java | 21 +- .../ui/controller/ViewThreadController.java | 10 +- .../controller/WatchSettingsController.java | 17 + .../ui/drawable/DropdownArrowDrawable.java | 17 + .../chan/ui/drawable/ThumbDrawable.java | 18 +- .../chan/ui/fragment/FolderPickFragment.java | 6 +- .../chan/ui/fragment/ImageViewFragment.java | 354 -- .../chan/ui/fragment/PostRepliesFragment.java | 175 - .../chan/ui/fragment/ReplyFragment.java | 609 ---- .../chan/ui/fragment/SettingsFragment.java | 201 -- .../chan/ui/fragment/ThreadFragment.java | 648 ---- .../org/floens/chan/ui/helper/PostHelper.java | 17 + .../chan/ui/helper/SwipeItemAnimator.java | 17 + .../floens/chan/ui/helper/SwipeListener.java | 19 +- .../floens/chan/ui/layout/ReplyLayout.java | 19 +- .../floens/chan/ui/layout/ThreadLayout.java | 6 +- .../floens/chan/ui/service/WatchNotifier.java | 17 +- .../chan/ui/settings/BooleanSettingView.java | 17 + .../chan/ui/settings/LinkSettingView.java | 17 + .../chan/ui/settings/ListSettingView.java | 17 + .../floens/chan/ui/settings/SettingView.java | 17 + .../chan/ui/settings/SettingsController.java | 17 + .../chan/ui/settings/SettingsGroup.java | 17 + .../chan/ui/settings/StringSettingView.java | 17 + .../chan/ui/toolbar/NavigationItem.java | 2 - .../org/floens/chan/ui/toolbar/Toolbar.java | 11 +- .../floens/chan/ui/toolbar/ToolbarMenu.java | 2 +- .../chan/ui/toolbar/ToolbarMenuItem.java | 10 +- .../chan/ui/transition/ImageTransition.java | 10 - .../floens/chan/ui/view/CrossfadeView.java | 17 + .../chan/ui/view/CustomNetworkImageView.java | 296 -- .../chan/ui/view/CustomScaleImageView.java | 18 + .../org/floens/chan/ui/view/DragGripView.java | 119 - .../org/floens/chan/ui/view/FloatingMenu.java | 1 - .../floens/chan/ui/view/HackyViewPager.java | 58 - .../org/floens/chan/ui/view/LoadingBar.java | 17 + .../floens/chan/ui/view/MultiImageView.java | 15 +- .../chan/ui/view/OptionalSwipeViewPager.java | 17 + .../org/floens/chan/ui/view/PostView.java | 633 ---- .../ui/view/SelectionListeningEditText.java | 17 + .../floens/chan/ui/view/ThumbnailView.java | 21 +- .../ui/view/TouchBlockingFrameLayout.java | 20 +- .../chan/ui/view/TransitionImageView.java | 17 + .../floens/chan/ui/view/ViewPagerAdapter.java | 21 +- .../org/floens/chan/utils/AndroidUtils.java | 35 +- .../java/org/floens/chan/utils/IconCache.java | 40 - .../org/floens/chan/utils/ImageSaver.java | 11 +- .../org/floens/chan/utils/ThemeHelper.java | 10 +- .../drawable-hdpi/ic_action_attachment.png | Bin 509 -> 0 bytes .../ic_action_attachment_dark.png | Bin 472 -> 0 bytes .../main/res/drawable-hdpi/ic_action_back.png | Bin 351 -> 0 bytes .../res/drawable-hdpi/ic_action_back_dark.png | Bin 296 -> 0 bytes .../res/drawable-hdpi/ic_action_cancel.png | Bin 438 -> 0 bytes .../drawable-hdpi/ic_action_cancel_dark.png | Bin 353 -> 0 bytes .../main/res/drawable-hdpi/ic_action_done.png | Bin 1320 -> 0 bytes .../res/drawable-hdpi/ic_action_done_dark.png | Bin 392 -> 0 bytes .../main/res/drawable-hdpi/ic_action_new.png | Bin 262 -> 0 bytes .../main/res/drawable-hdpi/ic_action_play.png | Bin 437 -> 0 bytes .../res/drawable-hdpi/ic_action_refresh.png | Bin 531 -> 0 bytes .../res/drawable-hdpi/ic_action_write.png | Bin 351 -> 0 bytes .../ic_arrow_back_black_24dp.png | Bin 0 -> 147 bytes .../ic_arrow_back_white_24dp.png | Bin 0 -> 152 bytes .../main/res/drawable-hdpi/ic_bookmark.png | Bin 330 -> 0 bytes .../res/drawable-hdpi/ic_bookmark_filled.png | Bin 273 -> 0 bytes .../ic_bookmark_outline_white_24dp.png | Bin 0 -> 239 bytes .../drawable-hdpi/ic_bookmark_white_24dp.png | Bin 0 -> 185 bytes .../drawable-hdpi/ic_create_white_24dp.png | Bin 0 -> 214 bytes .../res/drawable-hdpi/ic_done_black_24dp.png | Bin 0 -> 177 bytes .../res/drawable-hdpi/ic_done_white_24dp.png | Bin 0 -> 188 bytes .../src/main/res/drawable-hdpi/ic_drawer.png | Bin 2826 -> 0 bytes .../src/main/res/drawable-hdpi/ic_more.png | Bin 219 -> 0 bytes .../drawable-hdpi/ic_more_vert_white_24dp.png | Bin 0 -> 134 bytes .../drawable-hdpi/ic_refresh_white_24dp.png | Bin 0 -> 387 bytes .../main/res/drawable-hdpi/panel_shadow.9.png | Bin 111 -> 0 bytes .../progress_primary_holo_light.9.png | Bin 873 -> 0 bytes .../res/drawable-hdpi/skip_arrow_down.png | Bin 595 -> 0 bytes .../main/res/drawable-hdpi/skip_arrow_up.png | Bin 572 -> 0 bytes .../drawable-mdpi/ic_action_attachment.png | Bin 379 -> 0 bytes .../ic_action_attachment_dark.png | Bin 379 -> 0 bytes .../main/res/drawable-mdpi/ic_action_back.png | Bin 336 -> 0 bytes .../res/drawable-mdpi/ic_action_back_dark.png | Bin 272 -> 0 bytes .../res/drawable-mdpi/ic_action_cancel.png | Bin 328 -> 0 bytes .../drawable-mdpi/ic_action_cancel_dark.png | Bin 272 -> 0 bytes .../main/res/drawable-mdpi/ic_action_done.png | Bin 1197 -> 0 bytes .../res/drawable-mdpi/ic_action_done_dark.png | Bin 246 -> 0 bytes .../main/res/drawable-mdpi/ic_action_new.png | Bin 185 -> 0 bytes .../main/res/drawable-mdpi/ic_action_play.png | Bin 339 -> 0 bytes .../res/drawable-mdpi/ic_action_refresh.png | Bin 346 -> 0 bytes .../res/drawable-mdpi/ic_action_write.png | Bin 272 -> 0 bytes .../ic_arrow_back_black_24dp.png | Bin 0 -> 114 bytes .../ic_arrow_back_white_24dp.png | Bin 0 -> 118 bytes .../main/res/drawable-mdpi/ic_bookmark.png | Bin 262 -> 0 bytes .../res/drawable-mdpi/ic_bookmark_filled.png | Bin 223 -> 0 bytes .../ic_bookmark_outline_white_24dp.png | Bin 0 -> 176 bytes .../drawable-mdpi/ic_bookmark_white_24dp.png | Bin 0 -> 139 bytes .../drawable-mdpi/ic_create_white_24dp.png | Bin 0 -> 165 bytes .../res/drawable-mdpi/ic_done_black_24dp.png | Bin 0 -> 130 bytes .../res/drawable-mdpi/ic_done_white_24dp.png | Bin 0 -> 139 bytes .../src/main/res/drawable-mdpi/ic_drawer.png | Bin 2816 -> 0 bytes .../src/main/res/drawable-mdpi/ic_more.png | Bin 202 -> 0 bytes .../drawable-mdpi/ic_more_vert_white_24dp.png | Bin 0 -> 112 bytes .../drawable-mdpi/ic_refresh_white_24dp.png | Bin 0 -> 254 bytes .../main/res/drawable-mdpi/panel_shadow.9.png | Bin 100 -> 0 bytes .../progress_primary_holo_light.9.png | Bin 561 -> 0 bytes .../res/drawable-mdpi/skip_arrow_down.png | Bin 452 -> 0 bytes .../main/res/drawable-mdpi/skip_arrow_up.png | Bin 424 -> 0 bytes .../drawable-xhdpi/ic_action_attachment.png | Bin 653 -> 0 bytes .../ic_action_attachment_dark.png | Bin 590 -> 0 bytes .../res/drawable-xhdpi/ic_action_back.png | Bin 468 -> 0 bytes .../drawable-xhdpi/ic_action_back_dark.png | Bin 401 -> 0 bytes .../res/drawable-xhdpi/ic_action_cancel.png | Bin 513 -> 0 bytes .../drawable-xhdpi/ic_action_cancel_dark.png | Bin 415 -> 0 bytes .../res/drawable-xhdpi/ic_action_done.png | Bin 1546 -> 0 bytes .../drawable-xhdpi/ic_action_done_dark.png | Bin 475 -> 0 bytes .../main/res/drawable-xhdpi/ic_action_new.png | Bin 234 -> 0 bytes .../res/drawable-xhdpi/ic_action_play.png | Bin 522 -> 0 bytes .../res/drawable-xhdpi/ic_action_refresh.png | Bin 637 -> 0 bytes .../res/drawable-xhdpi/ic_action_write.png | Bin 378 -> 0 bytes .../ic_arrow_back_black_24dp.png | Bin 0 -> 146 bytes .../ic_arrow_back_white_24dp.png | Bin 0 -> 151 bytes .../main/res/drawable-xhdpi/ic_bookmark.png | Bin 401 -> 0 bytes .../res/drawable-xhdpi/ic_bookmark_filled.png | Bin 341 -> 0 bytes .../ic_bookmark_outline_white_24dp.png | Bin 0 -> 273 bytes .../drawable-xhdpi/ic_bookmark_white_24dp.png | Bin 0 -> 213 bytes .../drawable-xhdpi/ic_create_white_24dp.png | Bin 0 -> 239 bytes .../res/drawable-xhdpi/ic_done_black_24dp.png | Bin 0 -> 188 bytes .../res/drawable-xhdpi/ic_done_white_24dp.png | Bin 0 -> 199 bytes .../src/main/res/drawable-xhdpi/ic_drawer.png | Bin 1038 -> 0 bytes .../src/main/res/drawable-xhdpi/ic_more.png | Bin 269 -> 0 bytes .../ic_more_vert_white_24dp.png | Bin 0 -> 158 bytes .../drawable-xhdpi/ic_refresh_white_24dp.png | Bin 0 -> 509 bytes .../res/drawable-xhdpi/panel_shadow.9.png | Bin 119 -> 0 bytes .../progress_primary_holo_light.9.png | Bin 1285 -> 0 bytes .../res/drawable-xhdpi/skip_arrow_down.png | Bin 705 -> 0 bytes .../main/res/drawable-xhdpi/skip_arrow_up.png | Bin 690 -> 0 bytes .../drawable-xxhdpi/ic_action_attachment.png | Bin 926 -> 0 bytes .../ic_action_attachment_dark.png | Bin 822 -> 0 bytes .../res/drawable-xxhdpi/ic_action_back.png | Bin 527 -> 0 bytes .../drawable-xxhdpi/ic_action_back_dark.png | Bin 463 -> 0 bytes .../res/drawable-xxhdpi/ic_action_cancel.png | Bin 567 -> 0 bytes .../drawable-xxhdpi/ic_action_cancel_dark.png | Bin 574 -> 0 bytes .../res/drawable-xxhdpi/ic_action_done.png | Bin 649 -> 0 bytes .../drawable-xxhdpi/ic_action_done_dark.png | Bin 619 -> 0 bytes .../res/drawable-xxhdpi/ic_action_new.png | Bin 288 -> 0 bytes .../res/drawable-xxhdpi/ic_action_play.png | Bin 702 -> 0 bytes .../res/drawable-xxhdpi/ic_action_refresh.png | Bin 875 -> 0 bytes .../res/drawable-xxhdpi/ic_action_write.png | Bin 490 -> 0 bytes .../ic_arrow_back_black_24dp.png | Bin 0 -> 179 bytes .../ic_arrow_back_white_24dp.png | Bin 0 -> 188 bytes .../main/res/drawable-xxhdpi/ic_bookmark.png | Bin 525 -> 0 bytes .../drawable-xxhdpi/ic_bookmark_filled.png | Bin 419 -> 0 bytes .../ic_bookmark_outline_white_24dp.png | Bin 0 -> 370 bytes .../ic_bookmark_white_24dp.png | Bin 0 -> 273 bytes .../drawable-xxhdpi/ic_create_white_24dp.png | Bin 0 -> 302 bytes .../drawable-xxhdpi/ic_done_black_24dp.png | Bin 0 -> 227 bytes .../drawable-xxhdpi/ic_done_white_24dp.png | Bin 0 -> 255 bytes .../main/res/drawable-xxhdpi/ic_drawer.png | Bin 202 -> 0 bytes .../src/main/res/drawable-xxhdpi/ic_more.png | Bin 313 -> 0 bytes .../ic_more_vert_white_24dp.png | Bin 0 -> 216 bytes .../drawable-xxhdpi/ic_refresh_white_24dp.png | Bin 0 -> 734 bytes .../res/drawable-xxhdpi/panel_shadow.9.png | Bin 144 -> 0 bytes .../progress_primary_holo_light.9.png | Bin 3029 -> 0 bytes .../res/drawable-xxhdpi/skip_arrow_down.png | Bin 969 -> 0 bytes .../res/drawable-xxhdpi/skip_arrow_up.png | Bin 899 -> 0 bytes .../drawable-xxxhdpi/ic_action_refresh.png | Bin 1148 -> 0 bytes .../res/drawable-xxxhdpi/ic_action_write.png | Bin 632 -> 0 bytes .../ic_arrow_back_black_24dp.png | Bin 0 -> 216 bytes .../ic_arrow_back_white_24dp.png | Bin 0 -> 231 bytes .../main/res/drawable-xxxhdpi/ic_bookmark.png | Bin 659 -> 0 bytes .../drawable-xxxhdpi/ic_bookmark_filled.png | Bin 517 -> 0 bytes .../ic_bookmark_outline_white_24dp.png | Bin 0 -> 466 bytes .../ic_bookmark_white_24dp.png | Bin 0 -> 351 bytes .../drawable-xxxhdpi/ic_create_white_24dp.png | Bin 0 -> 355 bytes .../drawable-xxxhdpi/ic_done_black_24dp.png | Bin 0 -> 277 bytes .../drawable-xxxhdpi/ic_done_white_24dp.png | Bin 0 -> 308 bytes .../src/main/res/drawable-xxxhdpi/ic_more.png | Bin 393 -> 0 bytes .../ic_more_vert_white_24dp.png | Bin 0 -> 305 bytes .../ic_refresh_white_24dp.png | Bin 0 -> 967 bytes .../res/drawable-xxxhdpi/skip_arrow_down.png | Bin 1108 -> 0 bytes .../res/drawable-xxxhdpi/skip_arrow_up.png | Bin 1089 -> 0 bytes .../src/main/res/drawable/pin_icon_blue.xml | 27 - .../src/main/res/drawable/pin_icon_gray.xml | 27 - .../src/main/res/drawable/pin_icon_red.xml | 27 - .../preference_description_bottom.xml | 5 - .../drawable/preference_description_top.xml | 5 - .../main/res/drawable/progressbar_no_bg.xml | 24 - .../setting_description_bottom.xml} | 10 +- .../setting_description_top.xml} | 10 +- .../app/src/main/res/layout/activity_base.xml | 61 - .../src/main/res/layout/board_edit_item.xml | 42 - .../src/main/res/layout/board_select_add.xml | 30 - .../main/res/layout/board_select_spinner.xml | 29 - .../layout/board_select_spinner_dropdown.xml | 29 - .../src/main/res/layout/cell_board_edit.xml | 26 +- .../res/layout/cell_board_edit_header.xml | 22 +- .../app/src/main/res/layout/cell_header.xml | 26 +- Clover/app/src/main/res/layout/cell_link.xml | 26 +- Clover/app/src/main/res/layout/cell_pin.xml | 28 +- Clover/app/src/main/res/layout/cell_post.xml | 22 +- .../main/res/layout/cell_thread_status.xml | 24 +- .../main/res/layout/controller_board_edit.xml | 30 +- .../res/layout/controller_image_viewer.xml | 26 +- .../layout/controller_navigation_drawer.xml | 12 +- .../controller_navigation_image_viewer.xml | 4 +- .../main/res/layout/dialog_video_error.xml | 40 +- .../{watch_description.xml => dialog_web.xml} | 10 +- ...lder_pick.xml => fragment_folder_pick.xml} | 8 +- .../main/res/layout/header_switch_layout.xml | 63 - Clover/app/src/main/res/layout/image_view.xml | 48 - .../app/src/main/res/layout/layout_reply.xml | 6 - .../main/res/layout/layout_reply_input.xml | 18 +- .../main/res/layout/layout_thread_error.xml | 26 +- .../main/res/layout/layout_thread_list.xml | 18 +- Clover/app/src/main/res/layout/pin_item.xml | 84 - .../src/main/res/layout/pin_item_header.xml | 32 - .../app/src/main/res/layout/post_replies.xml | 8 +- .../res/layout/post_replies_bottombuttons.xml | 8 +- .../src/main/res/layout/preference_pass.xml | 44 - .../app/src/main/res/layout/reply_input.xml | 146 - Clover/app/src/main/res/layout/reply_view.xml | 84 - .../src/main/res/layout/setting_boolean.xml | 22 +- .../main/res/layout/setting_description.xml | 23 +- .../src/main/res/layout/setting_divider.xml | 18 +- .../app/src/main/res/layout/setting_group.xml | 38 +- .../app/src/main/res/layout/setting_link.xml | 22 +- .../app/src/main/res/layout/settings_pass.xml | 66 +- .../src/main/res/layout/settings_watch.xml | 20 +- Clover/app/src/main/res/layout/toolbar.xml | 26 - .../src/main/res/layout/toolbar_activity.xml | 30 - .../app/src/main/res/layout/toolbar_menu.xml | 46 +- .../src/main/res/layout/toolbar_menu_item.xml | 26 +- Clover/app/src/main/res/layout/web_dialog.xml | 11 - .../src/main/res/menu/action_bar_switch.xml | 27 - Clover/app/src/main/res/menu/base.xml | 144 - Clover/app/src/main/res/menu/board_edit.xml | 33 - Clover/app/src/main/res/menu/image_view.xml | 55 - Clover/app/src/main/res/menu/settings.xml | 25 - Clover/app/src/main/res/values/attrs.xml | 2 + Clover/app/src/main/res/values/colors.xml | 25 - Clover/app/src/main/res/values/dimens.xml | 25 - Clover/app/src/main/res/values/ids.xml | 30 - .../app/src/main/res/values/string_arrays.xml | 68 - Clover/app/src/main/res/values/strings.xml | 233 +- Clover/app/src/main/res/values/styles.xml | 156 +- .../app/src/main/res/values/watch_strings.xml | 41 - Clover/app/src/main/res/xml/preference.xml | 125 - .../src/main/res/xml/preference_advanced.xml | 65 - .../app/src/main/res/xml/preference_pass.xml | 33 - .../app/src/main/res/xml/preference_watch.xml | 68 - 324 files changed, 1820 insertions(+), 15226 deletions(-) delete mode 100644 Clover/app/src/main/java/com/mobeta/android/dslv/DragSortController.java delete mode 100644 Clover/app/src/main/java/com/mobeta/android/dslv/DragSortCursorAdapter.java delete mode 100644 Clover/app/src/main/java/com/mobeta/android/dslv/DragSortItemView.java delete mode 100644 Clover/app/src/main/java/com/mobeta/android/dslv/DragSortItemViewCheckable.java delete mode 100644 Clover/app/src/main/java/com/mobeta/android/dslv/DragSortListView.java delete mode 100644 Clover/app/src/main/java/com/mobeta/android/dslv/ResourceDragSortCursorAdapter.java delete mode 100644 Clover/app/src/main/java/com/mobeta/android/dslv/SimpleDragSortCursorAdapter.java delete mode 100644 Clover/app/src/main/java/com/mobeta/android/dslv/SimpleFloatViewManager.java create mode 100644 Clover/app/src/main/java/org/floens/chan/Chan.java rename Clover/app/src/main/java/org/floens/chan/{utils => core/cache}/FileCache.java (98%) delete mode 100644 Clover/app/src/main/java/org/floens/chan/core/loader/EndOfLineException.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/core/manager/ThreadManager.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/core/net/ByteArrayRequest.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/core/net/FileRequest.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/ui/ThemeActivity.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/ui/activity/AboutActivity.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/ui/activity/AdvancedSettingsActivity.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/ui/activity/BaseActivity.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/ui/activity/BoardEditor.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/ui/activity/ChanActivity.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/ui/activity/DeveloperActivity.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/ui/activity/ImageViewActivity.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/ui/activity/LicenseActivity.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/ui/activity/PassSettingsActivity.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/ui/activity/ReplyActivity.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/ui/activity/SettingsActivity.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/ui/activity/WatchSettingsActivity.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/ui/adapter/ImageViewAdapter.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/ui/adapter/PinnedAdapter.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/ui/animation/ScrollerRunnable.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/ui/animation/SwipeDismissListViewTouchListener.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/ui/animation/ViewFlipperAnimations.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/ui/fragment/ImageViewFragment.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/ui/fragment/PostRepliesFragment.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/ui/fragment/ReplyFragment.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/ui/fragment/SettingsFragment.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/ui/fragment/ThreadFragment.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/ui/transition/ImageTransition.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/ui/view/CustomNetworkImageView.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/ui/view/DragGripView.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/ui/view/HackyViewPager.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/ui/view/PostView.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/utils/IconCache.java delete mode 100644 Clover/app/src/main/res/drawable-hdpi/ic_action_attachment.png delete mode 100644 Clover/app/src/main/res/drawable-hdpi/ic_action_attachment_dark.png delete mode 100644 Clover/app/src/main/res/drawable-hdpi/ic_action_back.png delete mode 100644 Clover/app/src/main/res/drawable-hdpi/ic_action_back_dark.png delete mode 100644 Clover/app/src/main/res/drawable-hdpi/ic_action_cancel.png delete mode 100644 Clover/app/src/main/res/drawable-hdpi/ic_action_cancel_dark.png delete mode 100644 Clover/app/src/main/res/drawable-hdpi/ic_action_done.png delete mode 100644 Clover/app/src/main/res/drawable-hdpi/ic_action_done_dark.png delete mode 100644 Clover/app/src/main/res/drawable-hdpi/ic_action_new.png delete mode 100644 Clover/app/src/main/res/drawable-hdpi/ic_action_play.png delete mode 100644 Clover/app/src/main/res/drawable-hdpi/ic_action_refresh.png delete mode 100644 Clover/app/src/main/res/drawable-hdpi/ic_action_write.png create mode 100644 Clover/app/src/main/res/drawable-hdpi/ic_arrow_back_black_24dp.png create mode 100644 Clover/app/src/main/res/drawable-hdpi/ic_arrow_back_white_24dp.png delete mode 100644 Clover/app/src/main/res/drawable-hdpi/ic_bookmark.png delete mode 100644 Clover/app/src/main/res/drawable-hdpi/ic_bookmark_filled.png create mode 100644 Clover/app/src/main/res/drawable-hdpi/ic_bookmark_outline_white_24dp.png create mode 100644 Clover/app/src/main/res/drawable-hdpi/ic_bookmark_white_24dp.png create mode 100644 Clover/app/src/main/res/drawable-hdpi/ic_create_white_24dp.png create mode 100644 Clover/app/src/main/res/drawable-hdpi/ic_done_black_24dp.png create mode 100644 Clover/app/src/main/res/drawable-hdpi/ic_done_white_24dp.png delete mode 100644 Clover/app/src/main/res/drawable-hdpi/ic_drawer.png delete mode 100644 Clover/app/src/main/res/drawable-hdpi/ic_more.png create mode 100644 Clover/app/src/main/res/drawable-hdpi/ic_more_vert_white_24dp.png create mode 100644 Clover/app/src/main/res/drawable-hdpi/ic_refresh_white_24dp.png delete mode 100644 Clover/app/src/main/res/drawable-hdpi/panel_shadow.9.png delete mode 100644 Clover/app/src/main/res/drawable-hdpi/progress_primary_holo_light.9.png delete mode 100644 Clover/app/src/main/res/drawable-hdpi/skip_arrow_down.png delete mode 100644 Clover/app/src/main/res/drawable-hdpi/skip_arrow_up.png delete mode 100644 Clover/app/src/main/res/drawable-mdpi/ic_action_attachment.png delete mode 100644 Clover/app/src/main/res/drawable-mdpi/ic_action_attachment_dark.png delete mode 100644 Clover/app/src/main/res/drawable-mdpi/ic_action_back.png delete mode 100644 Clover/app/src/main/res/drawable-mdpi/ic_action_back_dark.png delete mode 100644 Clover/app/src/main/res/drawable-mdpi/ic_action_cancel.png delete mode 100644 Clover/app/src/main/res/drawable-mdpi/ic_action_cancel_dark.png delete mode 100644 Clover/app/src/main/res/drawable-mdpi/ic_action_done.png delete mode 100644 Clover/app/src/main/res/drawable-mdpi/ic_action_done_dark.png delete mode 100644 Clover/app/src/main/res/drawable-mdpi/ic_action_new.png delete mode 100644 Clover/app/src/main/res/drawable-mdpi/ic_action_play.png delete mode 100644 Clover/app/src/main/res/drawable-mdpi/ic_action_refresh.png delete mode 100644 Clover/app/src/main/res/drawable-mdpi/ic_action_write.png create mode 100644 Clover/app/src/main/res/drawable-mdpi/ic_arrow_back_black_24dp.png create mode 100644 Clover/app/src/main/res/drawable-mdpi/ic_arrow_back_white_24dp.png delete mode 100644 Clover/app/src/main/res/drawable-mdpi/ic_bookmark.png delete mode 100644 Clover/app/src/main/res/drawable-mdpi/ic_bookmark_filled.png create mode 100644 Clover/app/src/main/res/drawable-mdpi/ic_bookmark_outline_white_24dp.png create mode 100644 Clover/app/src/main/res/drawable-mdpi/ic_bookmark_white_24dp.png create mode 100644 Clover/app/src/main/res/drawable-mdpi/ic_create_white_24dp.png create mode 100644 Clover/app/src/main/res/drawable-mdpi/ic_done_black_24dp.png create mode 100644 Clover/app/src/main/res/drawable-mdpi/ic_done_white_24dp.png delete mode 100644 Clover/app/src/main/res/drawable-mdpi/ic_drawer.png delete mode 100644 Clover/app/src/main/res/drawable-mdpi/ic_more.png create mode 100644 Clover/app/src/main/res/drawable-mdpi/ic_more_vert_white_24dp.png create mode 100644 Clover/app/src/main/res/drawable-mdpi/ic_refresh_white_24dp.png delete mode 100644 Clover/app/src/main/res/drawable-mdpi/panel_shadow.9.png delete mode 100644 Clover/app/src/main/res/drawable-mdpi/progress_primary_holo_light.9.png delete mode 100644 Clover/app/src/main/res/drawable-mdpi/skip_arrow_down.png delete mode 100644 Clover/app/src/main/res/drawable-mdpi/skip_arrow_up.png delete mode 100644 Clover/app/src/main/res/drawable-xhdpi/ic_action_attachment.png delete mode 100644 Clover/app/src/main/res/drawable-xhdpi/ic_action_attachment_dark.png delete mode 100644 Clover/app/src/main/res/drawable-xhdpi/ic_action_back.png delete mode 100644 Clover/app/src/main/res/drawable-xhdpi/ic_action_back_dark.png delete mode 100644 Clover/app/src/main/res/drawable-xhdpi/ic_action_cancel.png delete mode 100644 Clover/app/src/main/res/drawable-xhdpi/ic_action_cancel_dark.png delete mode 100644 Clover/app/src/main/res/drawable-xhdpi/ic_action_done.png delete mode 100644 Clover/app/src/main/res/drawable-xhdpi/ic_action_done_dark.png delete mode 100644 Clover/app/src/main/res/drawable-xhdpi/ic_action_new.png delete mode 100644 Clover/app/src/main/res/drawable-xhdpi/ic_action_play.png delete mode 100644 Clover/app/src/main/res/drawable-xhdpi/ic_action_refresh.png delete mode 100644 Clover/app/src/main/res/drawable-xhdpi/ic_action_write.png create mode 100644 Clover/app/src/main/res/drawable-xhdpi/ic_arrow_back_black_24dp.png create mode 100644 Clover/app/src/main/res/drawable-xhdpi/ic_arrow_back_white_24dp.png delete mode 100644 Clover/app/src/main/res/drawable-xhdpi/ic_bookmark.png delete mode 100644 Clover/app/src/main/res/drawable-xhdpi/ic_bookmark_filled.png create mode 100644 Clover/app/src/main/res/drawable-xhdpi/ic_bookmark_outline_white_24dp.png create mode 100644 Clover/app/src/main/res/drawable-xhdpi/ic_bookmark_white_24dp.png create mode 100644 Clover/app/src/main/res/drawable-xhdpi/ic_create_white_24dp.png create mode 100644 Clover/app/src/main/res/drawable-xhdpi/ic_done_black_24dp.png create mode 100644 Clover/app/src/main/res/drawable-xhdpi/ic_done_white_24dp.png delete mode 100644 Clover/app/src/main/res/drawable-xhdpi/ic_drawer.png delete mode 100644 Clover/app/src/main/res/drawable-xhdpi/ic_more.png create mode 100644 Clover/app/src/main/res/drawable-xhdpi/ic_more_vert_white_24dp.png create mode 100644 Clover/app/src/main/res/drawable-xhdpi/ic_refresh_white_24dp.png delete mode 100644 Clover/app/src/main/res/drawable-xhdpi/panel_shadow.9.png delete mode 100644 Clover/app/src/main/res/drawable-xhdpi/progress_primary_holo_light.9.png delete mode 100644 Clover/app/src/main/res/drawable-xhdpi/skip_arrow_down.png delete mode 100644 Clover/app/src/main/res/drawable-xhdpi/skip_arrow_up.png delete mode 100644 Clover/app/src/main/res/drawable-xxhdpi/ic_action_attachment.png delete mode 100644 Clover/app/src/main/res/drawable-xxhdpi/ic_action_attachment_dark.png delete mode 100644 Clover/app/src/main/res/drawable-xxhdpi/ic_action_back.png delete mode 100644 Clover/app/src/main/res/drawable-xxhdpi/ic_action_back_dark.png delete mode 100644 Clover/app/src/main/res/drawable-xxhdpi/ic_action_cancel.png delete mode 100644 Clover/app/src/main/res/drawable-xxhdpi/ic_action_cancel_dark.png delete mode 100644 Clover/app/src/main/res/drawable-xxhdpi/ic_action_done.png delete mode 100644 Clover/app/src/main/res/drawable-xxhdpi/ic_action_done_dark.png delete mode 100644 Clover/app/src/main/res/drawable-xxhdpi/ic_action_new.png delete mode 100644 Clover/app/src/main/res/drawable-xxhdpi/ic_action_play.png delete mode 100644 Clover/app/src/main/res/drawable-xxhdpi/ic_action_refresh.png delete mode 100644 Clover/app/src/main/res/drawable-xxhdpi/ic_action_write.png create mode 100644 Clover/app/src/main/res/drawable-xxhdpi/ic_arrow_back_black_24dp.png create mode 100644 Clover/app/src/main/res/drawable-xxhdpi/ic_arrow_back_white_24dp.png delete mode 100644 Clover/app/src/main/res/drawable-xxhdpi/ic_bookmark.png delete mode 100644 Clover/app/src/main/res/drawable-xxhdpi/ic_bookmark_filled.png create mode 100644 Clover/app/src/main/res/drawable-xxhdpi/ic_bookmark_outline_white_24dp.png create mode 100644 Clover/app/src/main/res/drawable-xxhdpi/ic_bookmark_white_24dp.png create mode 100644 Clover/app/src/main/res/drawable-xxhdpi/ic_create_white_24dp.png create mode 100644 Clover/app/src/main/res/drawable-xxhdpi/ic_done_black_24dp.png create mode 100644 Clover/app/src/main/res/drawable-xxhdpi/ic_done_white_24dp.png delete mode 100644 Clover/app/src/main/res/drawable-xxhdpi/ic_drawer.png delete mode 100644 Clover/app/src/main/res/drawable-xxhdpi/ic_more.png create mode 100644 Clover/app/src/main/res/drawable-xxhdpi/ic_more_vert_white_24dp.png create mode 100644 Clover/app/src/main/res/drawable-xxhdpi/ic_refresh_white_24dp.png delete mode 100644 Clover/app/src/main/res/drawable-xxhdpi/panel_shadow.9.png delete mode 100644 Clover/app/src/main/res/drawable-xxhdpi/progress_primary_holo_light.9.png delete mode 100644 Clover/app/src/main/res/drawable-xxhdpi/skip_arrow_down.png delete mode 100644 Clover/app/src/main/res/drawable-xxhdpi/skip_arrow_up.png delete mode 100644 Clover/app/src/main/res/drawable-xxxhdpi/ic_action_refresh.png delete mode 100644 Clover/app/src/main/res/drawable-xxxhdpi/ic_action_write.png create mode 100644 Clover/app/src/main/res/drawable-xxxhdpi/ic_arrow_back_black_24dp.png create mode 100644 Clover/app/src/main/res/drawable-xxxhdpi/ic_arrow_back_white_24dp.png delete mode 100644 Clover/app/src/main/res/drawable-xxxhdpi/ic_bookmark.png delete mode 100644 Clover/app/src/main/res/drawable-xxxhdpi/ic_bookmark_filled.png create mode 100644 Clover/app/src/main/res/drawable-xxxhdpi/ic_bookmark_outline_white_24dp.png create mode 100644 Clover/app/src/main/res/drawable-xxxhdpi/ic_bookmark_white_24dp.png create mode 100644 Clover/app/src/main/res/drawable-xxxhdpi/ic_create_white_24dp.png create mode 100644 Clover/app/src/main/res/drawable-xxxhdpi/ic_done_black_24dp.png create mode 100644 Clover/app/src/main/res/drawable-xxxhdpi/ic_done_white_24dp.png delete mode 100644 Clover/app/src/main/res/drawable-xxxhdpi/ic_more.png create mode 100644 Clover/app/src/main/res/drawable-xxxhdpi/ic_more_vert_white_24dp.png create mode 100644 Clover/app/src/main/res/drawable-xxxhdpi/ic_refresh_white_24dp.png delete mode 100644 Clover/app/src/main/res/drawable-xxxhdpi/skip_arrow_down.png delete mode 100644 Clover/app/src/main/res/drawable-xxxhdpi/skip_arrow_up.png delete mode 100644 Clover/app/src/main/res/drawable/pin_icon_blue.xml delete mode 100644 Clover/app/src/main/res/drawable/pin_icon_gray.xml delete mode 100644 Clover/app/src/main/res/drawable/pin_icon_red.xml delete mode 100644 Clover/app/src/main/res/drawable/preference_description_bottom.xml delete mode 100644 Clover/app/src/main/res/drawable/preference_description_top.xml delete mode 100644 Clover/app/src/main/res/drawable/progressbar_no_bg.xml rename Clover/app/src/main/res/{anim/fade_out.xml => drawable/setting_description_bottom.xml} (79%) rename Clover/app/src/main/res/{anim/fade_in.xml => drawable/setting_description_top.xml} (79%) delete mode 100644 Clover/app/src/main/res/layout/activity_base.xml delete mode 100644 Clover/app/src/main/res/layout/board_edit_item.xml delete mode 100644 Clover/app/src/main/res/layout/board_select_add.xml delete mode 100644 Clover/app/src/main/res/layout/board_select_spinner.xml delete mode 100644 Clover/app/src/main/res/layout/board_select_spinner_dropdown.xml rename Clover/app/src/main/res/layout/{watch_description.xml => dialog_web.xml} (84%) rename Clover/app/src/main/res/layout/{folder_pick.xml => fragment_folder_pick.xml} (93%) delete mode 100644 Clover/app/src/main/res/layout/header_switch_layout.xml delete mode 100644 Clover/app/src/main/res/layout/image_view.xml delete mode 100644 Clover/app/src/main/res/layout/layout_reply.xml delete mode 100644 Clover/app/src/main/res/layout/pin_item.xml delete mode 100644 Clover/app/src/main/res/layout/pin_item_header.xml delete mode 100644 Clover/app/src/main/res/layout/preference_pass.xml delete mode 100644 Clover/app/src/main/res/layout/reply_input.xml delete mode 100644 Clover/app/src/main/res/layout/reply_view.xml delete mode 100644 Clover/app/src/main/res/layout/toolbar.xml delete mode 100644 Clover/app/src/main/res/layout/toolbar_activity.xml delete mode 100644 Clover/app/src/main/res/layout/web_dialog.xml delete mode 100644 Clover/app/src/main/res/menu/action_bar_switch.xml delete mode 100644 Clover/app/src/main/res/menu/base.xml delete mode 100644 Clover/app/src/main/res/menu/board_edit.xml delete mode 100644 Clover/app/src/main/res/menu/image_view.xml delete mode 100644 Clover/app/src/main/res/menu/settings.xml delete mode 100644 Clover/app/src/main/res/values/colors.xml delete mode 100644 Clover/app/src/main/res/values/dimens.xml delete mode 100644 Clover/app/src/main/res/values/ids.xml delete mode 100644 Clover/app/src/main/res/values/string_arrays.xml delete mode 100644 Clover/app/src/main/res/values/watch_strings.xml delete mode 100644 Clover/app/src/main/res/xml/preference.xml delete mode 100644 Clover/app/src/main/res/xml/preference_advanced.xml delete mode 100644 Clover/app/src/main/res/xml/preference_pass.xml delete mode 100644 Clover/app/src/main/res/xml/preference_watch.xml diff --git a/Clover/app/src/main/AndroidManifest.xml b/Clover/app/src/main/AndroidManifest.xml index 5ebdb2af..75d89b03 100644 --- a/Clover/app/src/main/AndroidManifest.xml +++ b/Clover/app/src/main/AndroidManifest.xml @@ -24,26 +24,22 @@ along with this program. If not, see . + android:theme="@style/Chan.Theme"> + + android:configChanges="keyboardHidden|orientation|screenSize" + android:label="@string/app_name"> - - - - + @@ -76,48 +72,15 @@ along with this program. If not, see . android:scheme="https" /> - - - - - - - - - - - - - + + + + + diff --git a/Clover/app/src/main/java/com/mobeta/android/dslv/DragSortController.java b/Clover/app/src/main/java/com/mobeta/android/dslv/DragSortController.java deleted file mode 100644 index 008dcd32..00000000 --- a/Clover/app/src/main/java/com/mobeta/android/dslv/DragSortController.java +++ /dev/null @@ -1,469 +0,0 @@ -package com.mobeta.android.dslv; - -import android.graphics.Point; -import android.view.GestureDetector; -import android.view.HapticFeedbackConstants; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewConfiguration; -import android.widget.AdapterView; - -/** - * Class that starts and stops item drags on a {@link DragSortListView} based on - * touch gestures. This class also inherits from {@link SimpleFloatViewManager}, - * which provides basic float View creation. - * - * An instance of this class is meant to be passed to the methods - * {@link DragSortListView#setTouchListener()} and - * {@link DragSortListView#setFloatViewManager()} of your - * {@link DragSortListView} instance. - */ -public class DragSortController extends SimpleFloatViewManager implements View.OnTouchListener, - GestureDetector.OnGestureListener { - - /** - * Drag init mode enum. - */ - public static final int ON_DOWN = 0; - public static final int ON_DRAG = 1; - public static final int ON_LONG_PRESS = 2; - - private int mDragInitMode = ON_DOWN; - - private boolean mSortEnabled = true; - - /** - * Remove mode enum. - */ - public static final int CLICK_REMOVE = 0; - public static final int FLING_REMOVE = 1; - - /** - * The current remove mode. - */ - private int mRemoveMode; - - private boolean mRemoveEnabled = false; - private boolean mIsRemoving = false; - - private GestureDetector mDetector; - - private GestureDetector mFlingRemoveDetector; - - private int mTouchSlop; - - public static final int MISS = -1; - - private int mHitPos = MISS; - private int mFlingHitPos = MISS; - - private int mClickRemoveHitPos = MISS; - - private int[] mTempLoc = new int[2]; - - private int mItemX; - private int mItemY; - - private int mCurrX; - private int mCurrY; - - private boolean mDragging = false; - - private float mFlingSpeed = 500f; - - private int mDragHandleId; - - private int mClickRemoveId; - - private int mFlingHandleId; - private boolean mCanDrag; - - private DragSortListView mDslv; - private int mPositionX; - - /** - * Calls {@link #DragSortController(DragSortListView, int)} with a 0 drag - * handle id, FLING_RIGHT_REMOVE remove mode, and ON_DOWN drag init. By - * default, sorting is enabled, and removal is disabled. - * - * @param dslv - * The DSLV instance - */ - public DragSortController(DragSortListView dslv) { - this(dslv, 0, ON_DOWN, FLING_REMOVE); - } - - public DragSortController(DragSortListView dslv, int dragHandleId, int dragInitMode, int removeMode) { - this(dslv, dragHandleId, dragInitMode, removeMode, 0); - } - - public DragSortController(DragSortListView dslv, int dragHandleId, int dragInitMode, int removeMode, - int clickRemoveId) { - this(dslv, dragHandleId, dragInitMode, removeMode, clickRemoveId, 0); - } - - /** - * By default, sorting is enabled, and removal is disabled. - * - * @param dslv - * The DSLV instance - * @param dragHandleId - * The resource id of the View that represents the drag handle in - * a list item. - */ - public DragSortController(DragSortListView dslv, int dragHandleId, int dragInitMode, int removeMode, - int clickRemoveId, int flingHandleId) { - super(dslv); - mDslv = dslv; - mDetector = new GestureDetector(dslv.getContext(), this); - mFlingRemoveDetector = new GestureDetector(dslv.getContext(), mFlingRemoveListener); - mFlingRemoveDetector.setIsLongpressEnabled(false); - mTouchSlop = ViewConfiguration.get(dslv.getContext()).getScaledTouchSlop(); - mDragHandleId = dragHandleId; - mClickRemoveId = clickRemoveId; - mFlingHandleId = flingHandleId; - setRemoveMode(removeMode); - setDragInitMode(dragInitMode); - } - - public int getDragInitMode() { - return mDragInitMode; - } - - /** - * Set how a drag is initiated. Needs to be one of {@link ON_DOWN}, - * {@link ON_DRAG}, or {@link ON_LONG_PRESS}. - * - * @param mode - * The drag init mode. - */ - public void setDragInitMode(int mode) { - mDragInitMode = mode; - } - - /** - * Enable/Disable list item sorting. Disabling is useful if only item - * removal is desired. Prevents drags in the vertical direction. - * - * @param enabled - * Set true to enable list item sorting. - */ - public void setSortEnabled(boolean enabled) { - mSortEnabled = enabled; - } - - public boolean isSortEnabled() { - return mSortEnabled; - } - - /** - * One of {@link CLICK_REMOVE}, {@link FLING_RIGHT_REMOVE}, - * {@link FLING_LEFT_REMOVE}, {@link SLIDE_RIGHT_REMOVE}, or - * {@link SLIDE_LEFT_REMOVE}. - */ - public void setRemoveMode(int mode) { - mRemoveMode = mode; - } - - public int getRemoveMode() { - return mRemoveMode; - } - - /** - * Enable/Disable item removal without affecting remove mode. - */ - public void setRemoveEnabled(boolean enabled) { - mRemoveEnabled = enabled; - } - - public boolean isRemoveEnabled() { - return mRemoveEnabled; - } - - /** - * Set the resource id for the View that represents the drag handle in a - * list item. - * - * @param id - * An android resource id. - */ - public void setDragHandleId(int id) { - mDragHandleId = id; - } - - /** - * Set the resource id for the View that represents the fling handle in a - * list item. - * - * @param id - * An android resource id. - */ - public void setFlingHandleId(int id) { - mFlingHandleId = id; - } - - /** - * Set the resource id for the View that represents click removal button. - * - * @param id - * An android resource id. - */ - public void setClickRemoveId(int id) { - mClickRemoveId = id; - } - - /** - * Sets flags to restrict certain motions of the floating View based on - * DragSortController settings (such as remove mode). Starts the drag on the - * DragSortListView. - * - * @param position - * The list item position (includes headers). - * @param deltaX - * Touch x-coord minus left edge of floating View. - * @param deltaY - * Touch y-coord minus top edge of floating View. - * - * @return True if drag started, false otherwise. - */ - public boolean startDrag(int position, int deltaX, int deltaY) { - - int dragFlags = 0; - if (mSortEnabled && !mIsRemoving) { - dragFlags |= DragSortListView.DRAG_POS_Y | DragSortListView.DRAG_NEG_Y; - } - if (mRemoveEnabled && mIsRemoving) { - dragFlags |= DragSortListView.DRAG_POS_X; - dragFlags |= DragSortListView.DRAG_NEG_X; - } - - mDragging = mDslv.startDrag(position - mDslv.getHeaderViewsCount(), dragFlags, deltaX, deltaY); - return mDragging; - } - - @Override - public boolean onTouch(View v, MotionEvent ev) { - if (!mDslv.isDragEnabled() || mDslv.listViewIntercepted()) { - return false; - } - - mDetector.onTouchEvent(ev); - if (mRemoveEnabled && mDragging && mRemoveMode == FLING_REMOVE) { - mFlingRemoveDetector.onTouchEvent(ev); - } - - int action = ev.getAction() & MotionEvent.ACTION_MASK; - switch (action) { - case MotionEvent.ACTION_DOWN: - mCurrX = (int) ev.getX(); - mCurrY = (int) ev.getY(); - break; - case MotionEvent.ACTION_UP: - if (mRemoveEnabled && mIsRemoving) { - int x = mPositionX >= 0 ? mPositionX : -mPositionX; - int removePoint = mDslv.getWidth() / 2; - if (x > removePoint) { - mDslv.stopDragWithVelocity(true, 0); - } - } - case MotionEvent.ACTION_CANCEL: - mIsRemoving = false; - mDragging = false; - break; - } - - return false; - } - - /** - * Overrides to provide fading when slide removal is enabled. - */ - @Override - public void onDragFloatView(View floatView, Point position, Point touch) { - - if (mRemoveEnabled && mIsRemoving) { - mPositionX = position.x; - } - } - - /** - * Get the position to start dragging based on the ACTION_DOWN MotionEvent. - * This function simply calls {@link #dragHandleHitPosition(MotionEvent)}. - * Override to change drag handle behavior; this function is called - * internally when an ACTION_DOWN event is detected. - * - * @param ev - * The ACTION_DOWN MotionEvent. - * - * @return The list position to drag if a drag-init gesture is detected; - * MISS if unsuccessful. - */ - public int startDragPosition(MotionEvent ev) { - return dragHandleHitPosition(ev); - } - - public int startFlingPosition(MotionEvent ev) { - return mRemoveMode == FLING_REMOVE ? flingHandleHitPosition(ev) : MISS; - } - - /** - * Checks for the touch of an item's drag handle (specified by - * {@link #setDragHandleId(int)}), and returns that item's position if a - * drag handle touch was detected. - * - * @param ev - * The ACTION_DOWN MotionEvent. - * - * @return The list position of the item whose drag handle was touched; MISS - * if unsuccessful. - */ - public int dragHandleHitPosition(MotionEvent ev) { - return viewIdHitPosition(ev, mDragHandleId); - } - - public int flingHandleHitPosition(MotionEvent ev) { - return viewIdHitPosition(ev, mFlingHandleId); - } - - public int viewIdHitPosition(MotionEvent ev, int id) { - final int x = (int) ev.getX(); - final int y = (int) ev.getY(); - - int touchPos = mDslv.pointToPosition(x, y); // includes headers/footers - - final int numHeaders = mDslv.getHeaderViewsCount(); - final int numFooters = mDslv.getFooterViewsCount(); - final int count = mDslv.getCount(); - - // Log.d("mobeta", "touch down on position " + itemnum); - // We're only interested if the touch was on an - // item that's not a header or footer. - if (touchPos != AdapterView.INVALID_POSITION && touchPos >= numHeaders && touchPos < (count - numFooters)) { - final View item = mDslv.getChildAt(touchPos - mDslv.getFirstVisiblePosition()); - final int rawX = (int) ev.getRawX(); - final int rawY = (int) ev.getRawY(); - - View dragBox = id == 0 ? item : (View) item.findViewById(id); - if (dragBox != null) { - dragBox.getLocationOnScreen(mTempLoc); - - if (rawX > mTempLoc[0] && rawY > mTempLoc[1] && rawX < mTempLoc[0] + dragBox.getWidth() - && rawY < mTempLoc[1] + dragBox.getHeight()) { - - mItemX = item.getLeft(); - mItemY = item.getTop(); - - return touchPos; - } - } - } - - return MISS; - } - - @Override - public boolean onDown(MotionEvent ev) { - if (mRemoveEnabled && mRemoveMode == CLICK_REMOVE) { - mClickRemoveHitPos = viewIdHitPosition(ev, mClickRemoveId); - } - - mHitPos = startDragPosition(ev); - if (mHitPos != MISS && mDragInitMode == ON_DOWN) { - startDrag(mHitPos, (int) ev.getX() - mItemX, (int) ev.getY() - mItemY); - } - - mIsRemoving = false; - mCanDrag = true; - mPositionX = 0; - mFlingHitPos = startFlingPosition(ev); - - return true; - } - - @Override - public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { - - final int x1 = (int) e1.getX(); - final int y1 = (int) e1.getY(); - final int x2 = (int) e2.getX(); - final int y2 = (int) e2.getY(); - final int deltaX = x2 - mItemX; - final int deltaY = y2 - mItemY; - - if (mCanDrag && !mDragging && (mHitPos != MISS || mFlingHitPos != MISS)) { - if (mHitPos != MISS) { - if (mDragInitMode == ON_DRAG && Math.abs(y2 - y1) > mTouchSlop && mSortEnabled) { - startDrag(mHitPos, deltaX, deltaY); - } else if (mDragInitMode != ON_DOWN && Math.abs(x2 - x1) > mTouchSlop && mRemoveEnabled) { - mIsRemoving = true; - startDrag(mFlingHitPos, deltaX, deltaY); - } - } else if (mFlingHitPos != MISS) { - if (Math.abs(x2 - x1) > mTouchSlop && mRemoveEnabled) { - mIsRemoving = true; - startDrag(mFlingHitPos, deltaX, deltaY); - } else if (Math.abs(y2 - y1) > mTouchSlop) { - mCanDrag = false; // if started to scroll the list then - // don't allow sorting nor fling-removing - } - } - } - // return whatever - return false; - } - - @Override - public void onLongPress(MotionEvent e) { - // Log.d("mobeta", "lift listener long pressed"); - if (mHitPos != MISS && mDragInitMode == ON_LONG_PRESS) { - mDslv.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - startDrag(mHitPos, mCurrX - mItemX, mCurrY - mItemY); - } - } - - // complete the OnGestureListener interface - @Override - public final boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { - return false; - } - - // complete the OnGestureListener interface - @Override - public boolean onSingleTapUp(MotionEvent ev) { - if (mRemoveEnabled && mRemoveMode == CLICK_REMOVE) { - if (mClickRemoveHitPos != MISS) { - mDslv.removeItem(mClickRemoveHitPos - mDslv.getHeaderViewsCount()); - } - } - return true; - } - - // complete the OnGestureListener interface - @Override - public void onShowPress(MotionEvent ev) { - // do nothing - } - - private GestureDetector.OnGestureListener mFlingRemoveListener = new GestureDetector.SimpleOnGestureListener() { - @Override - public final boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { - // Log.d("mobeta", "on fling remove called"); - if (mRemoveEnabled && mIsRemoving) { - int w = mDslv.getWidth(); - int minPos = w / 5; - if (velocityX > mFlingSpeed) { - if (mPositionX > -minPos) { - mDslv.stopDragWithVelocity(true, velocityX); - } - } else if (velocityX < -mFlingSpeed) { - if (mPositionX < minPos) { - mDslv.stopDragWithVelocity(true, velocityX); - } - } - mIsRemoving = false; - } - return false; - } - }; - -} diff --git a/Clover/app/src/main/java/com/mobeta/android/dslv/DragSortCursorAdapter.java b/Clover/app/src/main/java/com/mobeta/android/dslv/DragSortCursorAdapter.java deleted file mode 100644 index 0ba1e299..00000000 --- a/Clover/app/src/main/java/com/mobeta/android/dslv/DragSortCursorAdapter.java +++ /dev/null @@ -1,239 +0,0 @@ -package com.mobeta.android.dslv; - -import java.util.ArrayList; - -import android.content.Context; -import android.database.Cursor; -import android.support.v4.widget.CursorAdapter; -import android.util.SparseIntArray; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ListAdapter; - -/** - * A subclass of {@link android.widget.CursorAdapter} that provides reordering - * of the elements in the Cursor based on completed drag-sort operations. The - * reordering is a simple mapping of list positions into Cursor positions (the - * Cursor is unchanged). To persist changes made by drag-sorts, one can retrieve - * the mapping with the {@link #getCursorPositions()} method, which returns the - * reordered list of Cursor positions. - * - * An instance of this class is passed to - * {@link DragSortListView#setAdapter(ListAdapter)} and, since this class - * implements the {@link DragSortListView.DragSortListener} interface, it is - * automatically set as the DragSortListener for the DragSortListView instance. - */ -public abstract class DragSortCursorAdapter extends CursorAdapter implements DragSortListView.DragSortListener { - - public static final int REMOVED = -1; - - /** - * Key is ListView position, value is Cursor position - */ - private final SparseIntArray mListMapping = new SparseIntArray(); - - private final ArrayList mRemovedCursorPositions = new ArrayList(); - - @SuppressWarnings("deprecation") - public DragSortCursorAdapter(Context context, Cursor c) { - super(context, c); - } - - public DragSortCursorAdapter(Context context, Cursor c, boolean autoRequery) { - super(context, c, autoRequery); - } - - public DragSortCursorAdapter(Context context, Cursor c, int flags) { - super(context, c, flags); - } - - /** - * Swaps Cursor and clears list-Cursor mapping. - * - * @see android.widget.CursorAdapter#swapCursor(android.database.Cursor) - */ - @Override - public Cursor swapCursor(Cursor newCursor) { - Cursor old = super.swapCursor(newCursor); - resetMappings(); - return old; - } - - /** - * Changes Cursor and clears list-Cursor mapping. - * - * @see android.widget.CursorAdapter#changeCursor(android.database.Cursor) - */ - @Override - public void changeCursor(Cursor cursor) { - super.changeCursor(cursor); - resetMappings(); - } - - /** - * Resets list-cursor mapping. - */ - public void reset() { - resetMappings(); - notifyDataSetChanged(); - } - - private void resetMappings() { - mListMapping.clear(); - mRemovedCursorPositions.clear(); - } - - @Override - public Object getItem(int position) { - return super.getItem(mListMapping.get(position, position)); - } - - @Override - public long getItemId(int position) { - return super.getItemId(mListMapping.get(position, position)); - } - - @Override - public View getDropDownView(int position, View convertView, ViewGroup parent) { - return super.getDropDownView(mListMapping.get(position, position), convertView, parent); - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - return super.getView(mListMapping.get(position, position), convertView, parent); - } - - /** - * On drop, this updates the mapping between Cursor positions and ListView - * positions. The Cursor is unchanged. Retrieve the current mapping with - * {@link getCursorPositions()}. - * - * @see DragSortListView.DropListener#drop(int, int) - */ - @Override - public void drop(int from, int to) { - if (from != to) { - int cursorFrom = mListMapping.get(from, from); - - if (from > to) { - for (int i = from; i > to; --i) { - mListMapping.put(i, mListMapping.get(i - 1, i - 1)); - } - } else { - for (int i = from; i < to; ++i) { - mListMapping.put(i, mListMapping.get(i + 1, i + 1)); - } - } - mListMapping.put(to, cursorFrom); - - cleanMapping(); - notifyDataSetChanged(); - } - } - - /** - * On remove, this updates the mapping between Cursor positions and ListView - * positions. The Cursor is unchanged. Retrieve the current mapping with - * {@link getCursorPositions()}. - * - * @see DragSortListView.RemoveListener#remove(int) - */ - @Override - public void remove(int which) { - int cursorPos = mListMapping.get(which, which); - if (!mRemovedCursorPositions.contains(cursorPos)) { - mRemovedCursorPositions.add(cursorPos); - } - - int newCount = getCount(); - for (int i = which; i < newCount; ++i) { - mListMapping.put(i, mListMapping.get(i + 1, i + 1)); - } - - mListMapping.delete(newCount); - - cleanMapping(); - notifyDataSetChanged(); - } - - /** - * Does nothing. Just completes DragSortListener interface. - */ - @Override - public void drag(int from, int to) { - // do nothing - } - - /** - * Remove unnecessary mappings from sparse array. - */ - private void cleanMapping() { - ArrayList toRemove = new ArrayList(); - - int size = mListMapping.size(); - for (int i = 0; i < size; ++i) { - if (mListMapping.keyAt(i) == mListMapping.valueAt(i)) { - toRemove.add(mListMapping.keyAt(i)); - } - } - - size = toRemove.size(); - for (int i = 0; i < size; ++i) { - mListMapping.delete(toRemove.get(i)); - } - } - - @Override - public int getCount() { - return super.getCount() - mRemovedCursorPositions.size(); - } - - /** - * Get the Cursor position mapped to by the provided list position (given - * all previously handled drag-sort operations). - * - * @param position - * List position - * - * @return The mapped-to Cursor position - */ - public int getCursorPosition(int position) { - return mListMapping.get(position, position); - } - - /** - * Get the current order of Cursor positions presented by the list. - */ - public ArrayList getCursorPositions() { - ArrayList result = new ArrayList(); - - for (int i = 0; i < getCount(); ++i) { - result.add(mListMapping.get(i, i)); - } - - return result; - } - - /** - * Get the list position mapped to by the provided Cursor position. If the - * provided Cursor position has been removed by a drag-sort, this returns - * {@link #REMOVED}. - * - * @param cursorPosition - * A Cursor position - * @return The mapped-to list position or REMOVED - */ - public int getListPosition(int cursorPosition) { - if (mRemovedCursorPositions.contains(cursorPosition)) { - return REMOVED; - } - - int index = mListMapping.indexOfValue(cursorPosition); - if (index < 0) { - return cursorPosition; - } else { - return mListMapping.keyAt(index); - } - } - -} diff --git a/Clover/app/src/main/java/com/mobeta/android/dslv/DragSortItemView.java b/Clover/app/src/main/java/com/mobeta/android/dslv/DragSortItemView.java deleted file mode 100644 index c6d5eeb4..00000000 --- a/Clover/app/src/main/java/com/mobeta/android/dslv/DragSortItemView.java +++ /dev/null @@ -1,92 +0,0 @@ -package com.mobeta.android.dslv; - -import android.content.Context; -import android.view.Gravity; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AbsListView; - -/** - * Lightweight ViewGroup that wraps list items obtained from user's ListAdapter. - * ItemView expects a single child that has a definite height (i.e. the child's - * layout height is not MATCH_PARENT). The width of ItemView will always match - * the width of its child (that is, the width MeasureSpec given to ItemView is - * passed directly to the child, and the ItemView measured width is set to the - * child's measured width). The height of ItemView can be anything; the - * - * - * The purpose of this class is to optimize slide shuffle animations. - */ -public class DragSortItemView extends ViewGroup { - - private int mGravity = Gravity.TOP; - - public DragSortItemView(Context context) { - super(context); - - // always init with standard ListView layout params - setLayoutParams(new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT)); - - //setClipChildren(true); - } - - public void setGravity(int gravity) { - mGravity = gravity; - } - - public int getGravity() { - return mGravity; - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - final View child = getChildAt(0); - - if (child == null) { - return; - } - - if (mGravity == Gravity.TOP) { - child.layout(0, 0, getMeasuredWidth(), child.getMeasuredHeight()); - } else { - child.layout(0, getMeasuredHeight() - child.getMeasuredHeight(), getMeasuredWidth(), getMeasuredHeight()); - } - } - - /** - * - */ - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - - int height = MeasureSpec.getSize(heightMeasureSpec); - int width = MeasureSpec.getSize(widthMeasureSpec); - - int heightMode = MeasureSpec.getMode(heightMeasureSpec); - - final View child = getChildAt(0); - if (child == null) { - setMeasuredDimension(0, width); - return; - } - - if (child.isLayoutRequested()) { - // Always let child be as tall as it wants. - measureChild(child, widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); - } - - if (heightMode == MeasureSpec.UNSPECIFIED) { - ViewGroup.LayoutParams lp = getLayoutParams(); - - if (lp.height > 0) { - height = lp.height; - } else { - height = child.getMeasuredHeight(); - } - } - - setMeasuredDimension(width, height); - } - -} diff --git a/Clover/app/src/main/java/com/mobeta/android/dslv/DragSortItemViewCheckable.java b/Clover/app/src/main/java/com/mobeta/android/dslv/DragSortItemViewCheckable.java deleted file mode 100644 index a5a81235..00000000 --- a/Clover/app/src/main/java/com/mobeta/android/dslv/DragSortItemViewCheckable.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.mobeta.android.dslv; - -import android.content.Context; -import android.view.View; -import android.widget.Checkable; - -/** - * Lightweight ViewGroup that wraps list items obtained from user's ListAdapter. - * ItemView expects a single child that has a definite height (i.e. the child's - * layout height is not MATCH_PARENT). The width of ItemView will always match - * the width of its child (that is, the width MeasureSpec given to ItemView is - * passed directly to the child, and the ItemView measured width is set to the - * child's measured width). The height of ItemView can be anything; the - * - * - * The purpose of this class is to optimize slide shuffle animations. - */ -public class DragSortItemViewCheckable extends DragSortItemView implements Checkable { - - public DragSortItemViewCheckable(Context context) { - super(context); - } - - @Override - public boolean isChecked() { - View child = getChildAt(0); - if (child instanceof Checkable) - return ((Checkable) child).isChecked(); - else - return false; - } - - @Override - public void setChecked(boolean checked) { - View child = getChildAt(0); - if (child instanceof Checkable) - ((Checkable) child).setChecked(checked); - } - - @Override - public void toggle() { - View child = getChildAt(0); - if (child instanceof Checkable) - ((Checkable) child).toggle(); - } -} diff --git a/Clover/app/src/main/java/com/mobeta/android/dslv/DragSortListView.java b/Clover/app/src/main/java/com/mobeta/android/dslv/DragSortListView.java deleted file mode 100644 index ca2e618e..00000000 --- a/Clover/app/src/main/java/com/mobeta/android/dslv/DragSortListView.java +++ /dev/null @@ -1,2974 +0,0 @@ -/* - * DragSortListView. - * - * A subclass of the Android ListView component that enables drag - * and drop re-ordering of list items. - * - * Copyright 2012 Carl Bauer - * - * 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.mobeta.android.dslv; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.util.ArrayList; - -import android.content.Context; -import android.database.DataSetObserver; -import android.graphics.Canvas; -import android.graphics.Point; -import android.graphics.drawable.Drawable; -import android.os.Environment; -import android.os.SystemClock; -import android.util.AttributeSet; -import android.util.Log; -import android.util.SparseBooleanArray; -import android.util.SparseIntArray; -import android.view.Gravity; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AbsListView; -import android.widget.BaseAdapter; -import android.widget.Checkable; -import android.widget.ListAdapter; -import android.widget.ListView; - -/** - * ListView subclass that mediates drag and drop resorting of items. - * - * - * @author heycosmo - * - */ -@SuppressWarnings("unused") -public class DragSortListView extends ListView { - - /** - * The View that floats above the ListView and represents the dragged item. - */ - private View mFloatView; - - /** - * The float View location. First based on touch location and given deltaX - * and deltaY. Then restricted by callback to - * FloatViewManager.onDragFloatView(). Finally restricted by bounds of DSLV. - */ - private final Point mFloatLoc = new Point(); - - private final Point mTouchLoc = new Point(); - - /** - * The middle (in the y-direction) of the floating View. - */ - private int mFloatViewMid; - - /** - * Flag to make sure float View isn't measured twice - */ - private boolean mFloatViewOnMeasured = false; - - /** - * Watch the Adapter for data changes. Cancel a drag if coincident with a - * change. - */ - private final DataSetObserver mObserver; - - /** - * Transparency for the floating View (XML attribute). - */ - private final float mFloatAlpha = 1.0f; - private float mCurrFloatAlpha = 1.0f; - - /** - * While drag-sorting, the current position of the floating View. If - * dropped, the dragged item will land in this position. - */ - private int mFloatPos; - - /** - * The first expanded ListView position that helps represent the drop slot - * tracking the floating View. - */ - private int mFirstExpPos; - - /** - * The second expanded ListView position that helps represent the drop slot - * tracking the floating View. This can equal mFirstExpPos if there is no - * slide shuffle occurring; otherwise it is equal to mFirstExpPos + 1. - */ - private int mSecondExpPos; - - /** - * Flag set if slide shuffling is enabled. - */ - private final boolean mAnimate = false; - - /** - * The user dragged from this position. - */ - private int mSrcPos; - - /** - * Offset (in x) within the dragged item at which the user picked it up (or - * first touched down with the digitalis). - */ - private int mDragDeltaX; - - /** - * Offset (in y) within the dragged item at which the user picked it up (or - * first touched down with the digitalis). - */ - private int mDragDeltaY; - - /** - * The difference (in x) between screen coordinates and coordinates in this - * view. - */ - private int mOffsetX; - - /** - * The difference (in y) between screen coordinates and coordinates in this - * view. - */ - private int mOffsetY; - - /** - * A listener that receives callbacks whenever the floating View hovers over - * a new position. - */ - private DragListener mDragListener; - - /** - * A listener that receives a callback when the floating View is dropped. - */ - private DropListener mDropListener; - - /** - * A listener that receives a callback when the floating View (or more - * precisely the originally dragged item) is removed by one of the provided - * gestures. - */ - private RemoveListener mRemoveListener; - - /** - * Enable/Disable item dragging - * - * @attr name dslv:drag_enabled - */ - private boolean mDragEnabled = true; - - /** - * Drag state enum. - */ - private final static int IDLE = 0; - private final static int REMOVING = 1; - private final static int DROPPING = 2; - private final static int STOPPED = 3; - private final static int DRAGGING = 4; - - private int mDragState = IDLE; - - /** - * Height in pixels to which the originally dragged item is collapsed during - * a drag-sort. Currently, this value must be greater than zero. - */ - private final int mItemHeightCollapsed = 1; - - /** - * Height of the floating View. Stored for the purpose of providing the - * tracking drop slot. - */ - private int mFloatViewHeight; - - /** - * Convenience member. See above. - */ - private int mFloatViewHeightHalf; - - /** - * Save the given width spec for use in measuring children - */ - private int mWidthMeasureSpec = 0; - - /** - * Sample Views ultimately used for calculating the height of ListView items - * that are off-screen. - */ - private View[] mSampleViewTypes = new View[1]; - - /** - * Drag-scroll encapsulator! - */ - private final DragScroller mDragScroller; - - /** - * Determines the start of the upward drag-scroll region at the top of the - * ListView. Specified by a fraction of the ListView height, thus screen - * resolution agnostic. - */ - private float mDragUpScrollStartFrac = 1.0f / 3.0f; - - /** - * Determines the start of the downward drag-scroll region at the bottom of - * the ListView. Specified by a fraction of the ListView height, thus screen - * resolution agnostic. - */ - private float mDragDownScrollStartFrac = 1.0f / 3.0f; - - /** - * The following are calculated from the above fracs. - */ - private int mUpScrollStartY; - private int mDownScrollStartY; - private float mDownScrollStartYF; - private float mUpScrollStartYF; - - /** - * Calculated from above above and current ListView height. - */ - private float mDragUpScrollHeight; - - /** - * Calculated from above above and current ListView height. - */ - private float mDragDownScrollHeight; - - /** - * Maximum drag-scroll speed in pixels per ms. Only used with default linear - * drag-scroll profile. - */ - private float mMaxScrollSpeed = 0.5f; - - /** - * Defines the scroll speed during a drag-scroll. User can provide their - * own; this default is a simple linear profile where scroll speed increases - * linearly as the floating View nears the top/bottom of the ListView. - */ - private DragScrollProfile mScrollProfile = new DragScrollProfile() { - @Override - public float getSpeed(float w, long t) { - return mMaxScrollSpeed * w; - } - }; - - /** - * Current touch x. - */ - private int mX; - - /** - * Current touch y. - */ - private int mY; - - /** - * Last touch x. - */ - private int mLastX; - - /** - * Last touch y. - */ - private int mLastY; - - /** - * The touch y-coord at which drag started - */ - private int mDragStartY; - - /** - * Drag flag bit. Floating View can move in the positive x direction. - */ - public final static int DRAG_POS_X = 0x1; - - /** - * Drag flag bit. Floating View can move in the negative x direction. - */ - public final static int DRAG_NEG_X = 0x2; - - /** - * Drag flag bit. Floating View can move in the positive y direction. This - * is subtle. What this actually means is that, if enabled, the floating - * View can be dragged below its starting position. Remove in favor of - * upper-bounding item position? - */ - public final static int DRAG_POS_Y = 0x4; - - /** - * Drag flag bit. Floating View can move in the negative y direction. This - * is subtle. What this actually means is that the floating View can be - * dragged above its starting position. Remove in favor of lower-bounding - * item position? - */ - public final static int DRAG_NEG_Y = 0x8; - - /** - * Flags that determine limits on the motion of the floating View. See flags - * above. - */ - private int mDragFlags = 0; - - /** - * Last call to an on*TouchEvent was a call to onInterceptTouchEvent. - */ - private boolean mLastCallWasIntercept = false; - - /** - * A touch event is in progress. - */ - private boolean mInTouchEvent = false; - - /** - * Let the user customize the floating View. - */ - private FloatViewManager mFloatViewManager = null; - - /** - * Given to ListView to cancel its action when a drag-sort begins. - */ - private final MotionEvent mCancelEvent; - - /** - * Enum telling where to cancel the ListView action when a drag-sort begins - */ - private static final int NO_CANCEL = 0; - private static final int ON_TOUCH_EVENT = 1; - private static final int ON_INTERCEPT_TOUCH_EVENT = 2; - - /** - * Where to cancel the ListView action when a drag-sort begins - */ - private int mCancelMethod = NO_CANCEL; - - /** - * Determines when a slide shuffle animation starts. That is, defines how - * close to the edge of the drop slot the floating View must be to initiate - * the slide. - */ - private final float mSlideRegionFrac = 0.25f; - - /** - * Number between 0 and 1 indicating the relative location of a sliding item - * (only used if drag-sort animations are turned on). Nearly 1 means the - * item is at the top of the slide region (nearly full blank item is - * directly below). - */ - private float mSlideFrac = 0.0f; - - /** - * Wraps the user-provided ListAdapter. This is used to wrap each item View - * given by the user inside another View (currenly a RelativeLayout) which - * expands and collapses to simulate the item shuffling. - */ - private AdapterWrapper mAdapterWrapper; - - /** - * Turn on custom debugger. - */ - private final boolean mTrackDragSort = false; - - /** - * Debugging class. - */ - private DragSortTracker mDragSortTracker; - - /** - * Needed for adjusting item heights from within layoutChildren - */ - private boolean mBlockLayoutRequests = false; - - /** - * Set to true when a down event happens during drag sort; for example, when - * drag finish animations are playing. - */ - private boolean mIgnoreTouchEvent = false; - - /** - * Caches DragSortItemView child heights. Sometimes DSLV has to know the - * height of an offscreen item. Since ListView virtualizes these, DSLV must - * get the item from the ListAdapter to obtain its height. That process can - * be expensive, but often the same offscreen item will be requested many - * times in a row. Once an offscreen item height is calculated, we cache it - * in this guy. Actually, we cache the height of the child of the - * DragSortItemView since the item height changes often during a drag-sort. - */ - private static final int sCacheSize = 3; - private final HeightCache mChildHeightCache = new HeightCache(sCacheSize); - - private RemoveAnimator mRemoveAnimator; - - private LiftAnimator mLiftAnimator; - - private DropAnimator mDropAnimator; - - private boolean mUseRemoveVelocity; - private float mRemoveVelocityX = 0; - - public DragSortListView(Context context, AttributeSet attrs) { - super(context, attrs); - - int defaultDuration = 150; - int removeAnimDuration = defaultDuration; // ms - int dropAnimDuration = defaultDuration; // ms - - mDragScroller = new DragScroller(); - - float smoothness = 0.5f; - if (removeAnimDuration > 0) { - mRemoveAnimator = new RemoveAnimator(smoothness, removeAnimDuration); - } - // mLiftAnimator = new LiftAnimator(smoothness, 100); - if (dropAnimDuration > 0) { - mDropAnimator = new DropAnimator(smoothness, dropAnimDuration); - } - - mCancelEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0f, 0f, 0f, 0f, 0, 0f, 0f, 0, 0); - - // construct the dataset observer - mObserver = new DataSetObserver() { - private void cancel() { - if (mDragState == DRAGGING) { - cancelDrag(); - } - } - - @Override - public void onChanged() { - cancel(); - } - - @Override - public void onInvalidated() { - cancel(); - } - }; - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - mCancelEvent.recycle(); - } - - public boolean isDragging() { - return mDragState == DRAGGING; - } - - /** - * Usually called from a FloatViewManager. The float alpha will be reset to - * the xml-defined value every time a drag is stopped. - */ - public void setFloatAlpha(float alpha) { - mCurrFloatAlpha = alpha; - } - - public float getFloatAlpha() { - return mCurrFloatAlpha; - } - - /** - * Set maximum drag scroll speed in positions/second. Only applies if using - * default ScrollSpeedProfile. - * - * @param max - * Maximum scroll speed. - */ - public void setMaxScrollSpeed(float max) { - mMaxScrollSpeed = max; - } - - /** - * For each DragSortListView Listener interface implemented by - * adapter, this method calls the appropriate set*Listener - * method with adapter as the argument. - * - * @param adapter - * The ListAdapter providing data to back DragSortListView. - * - * @see android.widget.ListView#setAdapter(android.widget.ListAdapter) - */ - @Override - public void setAdapter(ListAdapter adapter) { - if (adapter != null) { - mAdapterWrapper = new AdapterWrapper(adapter); - adapter.registerDataSetObserver(mObserver); - - if (adapter instanceof DropListener) { - setDropListener((DropListener) adapter); - } - if (adapter instanceof DragListener) { - setDragListener((DragListener) adapter); - } - if (adapter instanceof RemoveListener) { - setRemoveListener((RemoveListener) adapter); - } - } else { - mAdapterWrapper = null; - } - - super.setAdapter(mAdapterWrapper); - } - - /** - * As opposed to {@link ListView#getAdapter()}, which returns a heavily - * wrapped ListAdapter (DragSortListView wraps the input ListAdapter {\emph - * and} ListView wraps the wrapped one). - * - * @return The ListAdapter set as the argument of {@link setAdapter()} - */ - public ListAdapter getInputAdapter() { - if (mAdapterWrapper == null) { - return null; - } else { - return mAdapterWrapper.getAdapter(); - } - } - - private class AdapterWrapper extends BaseAdapter { - private final ListAdapter mAdapter; - - public AdapterWrapper(ListAdapter adapter) { - super(); - mAdapter = adapter; - - mAdapter.registerDataSetObserver(new DataSetObserver() { - @Override - public void onChanged() { - notifyDataSetChanged(); - } - - @Override - public void onInvalidated() { - notifyDataSetInvalidated(); - } - }); - } - - public ListAdapter getAdapter() { - return mAdapter; - } - - @Override - public long getItemId(int position) { - return mAdapter.getItemId(position); - } - - @Override - public Object getItem(int position) { - return mAdapter.getItem(position); - } - - @Override - public int getCount() { - return mAdapter.getCount(); - } - - @Override - public boolean areAllItemsEnabled() { - return mAdapter.areAllItemsEnabled(); - } - - @Override - public boolean isEnabled(int position) { - return mAdapter.isEnabled(position); - } - - @Override - public int getItemViewType(int position) { - return mAdapter.getItemViewType(position); - } - - @Override - public int getViewTypeCount() { - return mAdapter.getViewTypeCount(); - } - - @Override - public boolean hasStableIds() { - return mAdapter.hasStableIds(); - } - - @Override - public boolean isEmpty() { - return mAdapter.isEmpty(); - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - - DragSortItemView v; - View child; - // Log.d("mobeta", - // "getView: position="+position+" convertView="+convertView); - if (convertView != null) { - v = (DragSortItemView) convertView; - View oldChild = v.getChildAt(0); - - child = mAdapter.getView(position, oldChild, DragSortListView.this); - if (child != oldChild) { - // shouldn't get here if user is reusing convertViews - // properly - if (oldChild != null) { - v.removeViewAt(0); - } - v.addView(child); - } - } else { - child = mAdapter.getView(position, null, DragSortListView.this); - if (child instanceof Checkable) { - v = new DragSortItemViewCheckable(getContext()); - } else { - v = new DragSortItemView(getContext()); - } - v.setLayoutParams(new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT)); - v.addView(child); - } - - // Set the correct item height given drag state; passed - // View needs to be measured if measurement is required. - adjustItem(position + getHeaderViewsCount(), v, true); - - return v; - } - } - - private void drawDivider(int expPosition, Canvas canvas) { - - final Drawable divider = getDivider(); - final int dividerHeight = getDividerHeight(); - // Log.d("mobeta", "div="+divider+" divH="+dividerHeight); - - if (divider != null && dividerHeight != 0) { - final ViewGroup expItem = (ViewGroup) getChildAt(expPosition - getFirstVisiblePosition()); - if (expItem != null) { - final int l = getPaddingLeft(); - final int r = getWidth() - getPaddingRight(); - final int t; - final int b; - - final int childHeight = expItem.getChildAt(0).getHeight(); - - if (expPosition > mSrcPos) { - t = expItem.getTop() + childHeight; - b = t + dividerHeight; - } else { - b = expItem.getBottom() - childHeight; - t = b - dividerHeight; - } - // Log.d("mobeta", "l="+l+" t="+t+" r="+r+" b="+b); - - // Have to clip to support ColorDrawable on <= Gingerbread - canvas.save(); - canvas.clipRect(l, t, r, b); - divider.setBounds(l, t, r, b); - divider.draw(canvas); - canvas.restore(); - } - } - } - - @Override - protected void dispatchDraw(Canvas canvas) { - super.dispatchDraw(canvas); - - if (mDragState != IDLE) { - // draw the divider over the expanded item - if (mFirstExpPos != mSrcPos) { - drawDivider(mFirstExpPos, canvas); - } - if (mSecondExpPos != mFirstExpPos && mSecondExpPos != mSrcPos) { - drawDivider(mSecondExpPos, canvas); - } - } - - if (mFloatView != null) { - // draw the float view over everything - final int w = mFloatView.getWidth(); - final int h = mFloatView.getHeight(); - - int x = mFloatLoc.x; - - int width = getWidth(); - if (x < 0) - x = -x; - float alphaMod; - if (x < width) { - alphaMod = ((float) (width - x)) / ((float) width); - alphaMod *= alphaMod; - } else { - alphaMod = 0; - } - - final int alpha = (int) (255f * mCurrFloatAlpha * alphaMod); - - canvas.save(); - // Log.d("mobeta", "clip rect bounds: " + canvas.getClipBounds()); - canvas.translate(mFloatLoc.x, mFloatLoc.y); - canvas.clipRect(0, 0, w, h); - - // Log.d("mobeta", "clip rect bounds: " + canvas.getClipBounds()); - canvas.saveLayerAlpha(0, 0, w, h, alpha, Canvas.ALL_SAVE_FLAG); - mFloatView.draw(canvas); - canvas.restore(); - canvas.restore(); - } - } - - private int getItemHeight(int position) { - View v = getChildAt(position - getFirstVisiblePosition()); - - if (v != null) { - // item is onscreen, just get the height of the View - return v.getHeight(); - } else { - // item is offscreen. get child height and calculate - // item height based on current shuffle state - return calcItemHeight(position, getChildHeight(position)); - } - } - - private void printPosData() { - Log.d("mobeta", "mSrcPos=" + mSrcPos + " mFirstExpPos=" + mFirstExpPos + " mSecondExpPos=" + mSecondExpPos); - } - - private class HeightCache { - - private final SparseIntArray mMap; - private final ArrayList mOrder; - private final int mMaxSize; - - public HeightCache(int size) { - mMap = new SparseIntArray(size); - mOrder = new ArrayList(size); - mMaxSize = size; - } - - /** - * Add item height at position if doesn't already exist. - */ - public void add(int position, int height) { - int currHeight = mMap.get(position, -1); - if (currHeight != height) { - if (currHeight == -1) { - if (mMap.size() == mMaxSize) { - // remove oldest entry - mMap.delete(mOrder.remove(0)); - } - } else { - // move position to newest slot - mOrder.remove((Integer) position); - } - mMap.put(position, height); - mOrder.add(position); - } - } - - public int get(int position) { - return mMap.get(position, -1); - } - - public void clear() { - mMap.clear(); - mOrder.clear(); - } - - } - - /** - * Get the shuffle edge for item at position when top of item is at y-coord - * top. Assumes that current item heights are consistent with current float - * view location and thus expanded positions and slide fraction. i.e. Should - * not be called between update of expanded positions/slide fraction and - * layoutChildren. - * - * @param position - * @param top - * @param height - * Height of item at position. If -1, this function calculates - * this height. - * - * @return Shuffle line between position-1 and position (for the given view - * of the list; that is, for when top of item at position has - * y-coord of given `top`). If floating View (treated as horizontal - * line) is dropped immediately above this line, it lands in - * position-1. If dropped immediately below this line, it lands in - * position. - */ - private int getShuffleEdge(int position, int top) { - - final int numHeaders = getHeaderViewsCount(); - final int numFooters = getFooterViewsCount(); - - // shuffle edges are defined between items that can be - // dragged; there are N-1 of them if there are N draggable - // items. - - if (position <= numHeaders || (position >= getCount() - numFooters)) { - return top; - } - - int divHeight = getDividerHeight(); - - int edge; - - int maxBlankHeight = mFloatViewHeight - mItemHeightCollapsed; - int childHeight = getChildHeight(position); - int itemHeight = getItemHeight(position); - - // first calculate top of item given that floating View is - // centered over src position - int otop = top; - if (mSecondExpPos <= mSrcPos) { - // items are expanded on and/or above the source position - - if (position == mSecondExpPos && mFirstExpPos != mSecondExpPos) { - if (position == mSrcPos) { - otop = top + itemHeight - mFloatViewHeight; - } else { - int blankHeight = itemHeight - childHeight; - otop = top + blankHeight - maxBlankHeight; - } - } else if (position > mSecondExpPos && position <= mSrcPos) { - otop = top - maxBlankHeight; - } - - } else { - // items are expanded on and/or below the source position - - if (position > mSrcPos && position <= mFirstExpPos) { - otop = top + maxBlankHeight; - } else if (position == mSecondExpPos && mFirstExpPos != mSecondExpPos) { - int blankHeight = itemHeight - childHeight; - otop = top + blankHeight; - } - } - - // otop is set - if (position <= mSrcPos) { - edge = otop + (mFloatViewHeight - divHeight - getChildHeight(position - 1)) / 2; - } else { - edge = otop + (childHeight - divHeight - mFloatViewHeight) / 2; - } - - return edge; - } - - private boolean updatePositions() { - - final int first = getFirstVisiblePosition(); - int startPos = mFirstExpPos; - View startView = getChildAt(startPos - first); - - if (startView == null) { - startPos = first + getChildCount() / 2; - startView = getChildAt(startPos - first); - } - int startTop = startView.getTop(); - - int itemHeight = startView.getHeight(); - - int edge = getShuffleEdge(startPos, startTop); - int lastEdge = edge; - - int divHeight = getDividerHeight(); - - // Log.d("mobeta", "float mid="+mFloatViewMid); - - int itemPos = startPos; - int itemTop = startTop; - if (mFloatViewMid < edge) { - // scanning up for float position - // Log.d("mobeta", " edge="+edge); - while (itemPos >= 0) { - itemPos--; - itemHeight = getItemHeight(itemPos); - - if (itemPos == 0) { - edge = itemTop - divHeight - itemHeight; - break; - } - - itemTop -= itemHeight + divHeight; - edge = getShuffleEdge(itemPos, itemTop); - // Log.d("mobeta", " edge="+edge); - - if (mFloatViewMid >= edge) { - break; - } - - lastEdge = edge; - } - } else { - // scanning down for float position - // Log.d("mobeta", " edge="+edge); - final int count = getCount(); - while (itemPos < count) { - if (itemPos == count - 1) { - edge = itemTop + divHeight + itemHeight; - break; - } - - itemTop += divHeight + itemHeight; - itemHeight = getItemHeight(itemPos + 1); - edge = getShuffleEdge(itemPos + 1, itemTop); - // Log.d("mobeta", " edge="+edge); - - // test for hit - if (mFloatViewMid < edge) { - break; - } - - lastEdge = edge; - itemPos++; - } - } - - final int numHeaders = getHeaderViewsCount(); - final int numFooters = getFooterViewsCount(); - - boolean updated = false; - - int oldFirstExpPos = mFirstExpPos; - int oldSecondExpPos = mSecondExpPos; - float oldSlideFrac = mSlideFrac; - - if (mAnimate) { - int edgeToEdge = Math.abs(edge - lastEdge); - - int edgeTop, edgeBottom; - if (mFloatViewMid < edge) { - edgeBottom = edge; - edgeTop = lastEdge; - } else { - edgeTop = edge; - edgeBottom = lastEdge; - } - // Log.d("mobeta", "edgeTop="+edgeTop+" edgeBot="+edgeBottom); - - int slideRgnHeight = (int) (0.5f * mSlideRegionFrac * edgeToEdge); - float slideRgnHeightF = slideRgnHeight; - int slideEdgeTop = edgeTop + slideRgnHeight; - int slideEdgeBottom = edgeBottom - slideRgnHeight; - - // Three regions - if (mFloatViewMid < slideEdgeTop) { - mFirstExpPos = itemPos - 1; - mSecondExpPos = itemPos; - mSlideFrac = 0.5f * (slideEdgeTop - mFloatViewMid) / slideRgnHeightF; - // Log.d("mobeta", - // "firstExp="+mFirstExpPos+" secExp="+mSecondExpPos+" slideFrac="+mSlideFrac); - } else if (mFloatViewMid < slideEdgeBottom) { - mFirstExpPos = itemPos; - mSecondExpPos = itemPos; - } else { - mFirstExpPos = itemPos; - mSecondExpPos = itemPos + 1; - mSlideFrac = 0.5f * (1.0f + (edgeBottom - mFloatViewMid) / slideRgnHeightF); - // Log.d("mobeta", - // "firstExp="+mFirstExpPos+" secExp="+mSecondExpPos+" slideFrac="+mSlideFrac); - } - - } else { - mFirstExpPos = itemPos; - mSecondExpPos = itemPos; - } - - // correct for headers and footers - if (mFirstExpPos < numHeaders) { - itemPos = numHeaders; - mFirstExpPos = itemPos; - mSecondExpPos = itemPos; - } else if (mSecondExpPos >= getCount() - numFooters) { - itemPos = getCount() - numFooters - 1; - mFirstExpPos = itemPos; - mSecondExpPos = itemPos; - } - - if (mFirstExpPos != oldFirstExpPos || mSecondExpPos != oldSecondExpPos || mSlideFrac != oldSlideFrac) { - updated = true; - } - - if (itemPos != mFloatPos) { - if (mDragListener != null) { - mDragListener.drag(mFloatPos - numHeaders, itemPos - numHeaders); - } - - mFloatPos = itemPos; - updated = true; - } - - return updated; - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - - if (mTrackDragSort) { - mDragSortTracker.appendState(); - } - } - - private class SmoothAnimator implements Runnable { - protected long mStartTime; - - private final float mDurationF; - - private final float mAlpha; - private final float mA, mB, mC; - - private float mD; - - private boolean mCanceled; - - public SmoothAnimator(float smoothness, int duration) { - mAlpha = smoothness; - mDurationF = duration; - mA = mD = 1f / (2f * mAlpha * (1f - mAlpha)); - mB = mAlpha / (2f * (mAlpha - 1f)); - mC = 1f / (1f - mAlpha); - } - - public float transform(float frac) { - if (frac < mAlpha) { - return mA * frac * frac; - } else if (frac < 1f - mAlpha) { - return mB + mC * frac; - } else { - return 1f - mD * (frac - 1f) * (frac - 1f); - } - } - - public void start() { - mStartTime = SystemClock.uptimeMillis(); - mCanceled = false; - onStart(); - post(this); - } - - public void cancel() { - mCanceled = true; - } - - public void onStart() { - // stub - } - - public void onUpdate(float frac, float smoothFrac) { - // stub - } - - public void onStop() { - // stub - } - - @Override - public void run() { - if (mCanceled) { - return; - } - - float fraction = (SystemClock.uptimeMillis() - mStartTime) / mDurationF; - - if (fraction >= 1f) { - onUpdate(1f, 1f); - onStop(); - } else { - onUpdate(fraction, transform(fraction)); - post(this); - } - } - } - - /** - * Centers floating View under touch point. - */ - private class LiftAnimator extends SmoothAnimator { - - private float mInitDragDeltaY; - private float mFinalDragDeltaY; - - public LiftAnimator(float smoothness, int duration) { - super(smoothness, duration); - } - - @Override - public void onStart() { - mInitDragDeltaY = mDragDeltaY; - mFinalDragDeltaY = mFloatViewHeightHalf; - } - - @Override - public void onUpdate(float frac, float smoothFrac) { - if (mDragState != DRAGGING) { - cancel(); - } else { - mDragDeltaY = (int) (smoothFrac * mFinalDragDeltaY + (1f - smoothFrac) * mInitDragDeltaY); - mFloatLoc.y = mY - mDragDeltaY; - doDragFloatView(true); - } - } - } - - /** - * Centers floating View over drop slot before destroying. - */ - private class DropAnimator extends SmoothAnimator { - - private int mDropPos; - private int srcPos; - private float mInitDeltaY; - private float mInitDeltaX; - - public DropAnimator(float smoothness, int duration) { - super(smoothness, duration); - } - - @Override - public void onStart() { - mDropPos = mFloatPos; - srcPos = mSrcPos; - mDragState = DROPPING; - mInitDeltaY = mFloatLoc.y - getTargetY(); - mInitDeltaX = mFloatLoc.x - getPaddingLeft(); - } - - private int getTargetY() { - final int first = getFirstVisiblePosition(); - final int otherAdjust = (mItemHeightCollapsed + getDividerHeight()) / 2; - View v = getChildAt(mDropPos - first); - int targetY = -1; - if (v != null) { - if (mDropPos == srcPos) { - targetY = v.getTop(); - } else if (mDropPos < srcPos) { - // expanded down - targetY = v.getTop() - otherAdjust; - } else { - // expanded up - targetY = v.getBottom() + otherAdjust - mFloatViewHeight; - } - } else { - // drop position is not on screen?? no animation - cancel(); - } - - return targetY; - } - - @Override - public void onUpdate(float frac, float smoothFrac) { - final int targetY = getTargetY(); - final int targetX = getPaddingLeft(); - final float deltaY = mFloatLoc.y - targetY; - final float deltaX = mFloatLoc.x - targetX; - final float f = 1f - smoothFrac; - if (f < Math.abs(deltaY / mInitDeltaY) || f < Math.abs(deltaX / mInitDeltaX)) { - mFloatLoc.y = targetY + (int) (mInitDeltaY * f); - mFloatLoc.x = getPaddingLeft() + (int) (mInitDeltaX * f); - doDragFloatView(true); - } - } - - @Override - public void onStop() { - dropFloatView(); - } - - } - - /** - * Collapses expanded items. - */ - private class RemoveAnimator extends SmoothAnimator { - - private float mFloatLocX; - private float mFirstStartBlank; - private float mSecondStartBlank; - - private int mFirstChildHeight = -1; - private int mSecondChildHeight = -1; - - private int mFirstPos; - private int mSecondPos; - private int srcPos; - - public RemoveAnimator(float smoothness, int duration) { - super(smoothness, duration); - } - - @Override - public void onStart() { - mFirstChildHeight = -1; - mSecondChildHeight = -1; - mFirstPos = mFirstExpPos; - mSecondPos = mSecondExpPos; - srcPos = mSrcPos; - mDragState = REMOVING; - - mFloatLocX = mFloatLoc.x; - if (mUseRemoveVelocity) { - float minVelocity = 2f * getWidth(); - if (mRemoveVelocityX == 0) { - mRemoveVelocityX = (mFloatLocX < 0 ? -1 : 1) * minVelocity; - } else { - minVelocity *= 2; - if (mRemoveVelocityX < 0 && mRemoveVelocityX > -minVelocity) - mRemoveVelocityX = -minVelocity; - else if (mRemoveVelocityX > 0 && mRemoveVelocityX < minVelocity) - mRemoveVelocityX = minVelocity; - } - } else { - destroyFloatView(); - } - } - - @Override - public void onUpdate(float frac, float smoothFrac) { - float f = 1f - smoothFrac; - - final int firstVis = getFirstVisiblePosition(); - View item = getChildAt(mFirstPos - firstVis); - ViewGroup.LayoutParams lp; - int blank; - - if (mUseRemoveVelocity) { - float dt = (float) (SystemClock.uptimeMillis() - mStartTime) / 1000; - if (dt == 0) - return; - float dx = mRemoveVelocityX * dt; - int w = getWidth(); - mRemoveVelocityX += (mRemoveVelocityX > 0 ? 1 : -1) * dt * w; - mFloatLocX += dx; - mFloatLoc.x = (int) mFloatLocX; - if (mFloatLocX < w && mFloatLocX > -w) { - mStartTime = SystemClock.uptimeMillis(); - doDragFloatView(true); - return; - } - } - - if (item != null) { - if (mFirstChildHeight == -1) { - mFirstChildHeight = getChildHeight(mFirstPos, item, false); - mFirstStartBlank = item.getHeight() - mFirstChildHeight; - } - blank = Math.max((int) (f * mFirstStartBlank), 1); - lp = item.getLayoutParams(); - lp.height = mFirstChildHeight + blank; - item.setLayoutParams(lp); - } - if (mSecondPos != mFirstPos) { - item = getChildAt(mSecondPos - firstVis); - if (item != null) { - if (mSecondChildHeight == -1) { - mSecondChildHeight = getChildHeight(mSecondPos, item, false); - mSecondStartBlank = item.getHeight() - mSecondChildHeight; - } - blank = Math.max((int) (f * mSecondStartBlank), 1); - lp = item.getLayoutParams(); - lp.height = mSecondChildHeight + blank; - item.setLayoutParams(lp); - } - } - } - - @Override - public void onStop() { - doRemoveItem(); - } - } - - public void removeItem(int which) { - - mUseRemoveVelocity = false; - removeItem(which, 0); - } - - /** - * Removes an item from the list and animates the removal. - * - * @param which - * Position to remove (NOTE: headers/footers ignored! this is a - * position in your input ListAdapter). - * @param velocityX - */ - public void removeItem(int which, float velocityX) { - if (mDragState == IDLE || mDragState == DRAGGING) { - - if (mDragState == IDLE) { - // called from outside drag-sort - mSrcPos = getHeaderViewsCount() + which; - mFirstExpPos = mSrcPos; - mSecondExpPos = mSrcPos; - mFloatPos = mSrcPos; - View v = getChildAt(mSrcPos - getFirstVisiblePosition()); - if (v != null) { - v.setVisibility(View.INVISIBLE); - } - } - - mDragState = REMOVING; - mRemoveVelocityX = velocityX; - - if (mInTouchEvent) { - switch (mCancelMethod) { - case ON_TOUCH_EVENT: - super.onTouchEvent(mCancelEvent); - break; - case ON_INTERCEPT_TOUCH_EVENT: - super.onInterceptTouchEvent(mCancelEvent); - break; - } - } - - if (mRemoveAnimator != null) { - mRemoveAnimator.start(); - } else { - doRemoveItem(which); - } - } - } - - /** - * Move an item, bypassing the drag-sort process. Simply calls through to - * {@link DropListener#drop(int, int)}. - * - * @param from - * Position to move (NOTE: headers/footers ignored! this is a - * position in your input ListAdapter). - * @param to - * Target position (NOTE: headers/footers ignored! this is a - * position in your input ListAdapter). - */ - public void moveItem(int from, int to) { - if (mDropListener != null) { - final int count = getInputAdapter().getCount(); - if (from >= 0 && from < count && to >= 0 && to < count) { - mDropListener.drop(from, to); - } - } - } - - /** - * Cancel a drag. Calls {@link #stopDrag(boolean, boolean)} with - * true as the first argument. - */ - public void cancelDrag() { - if (mDragState == DRAGGING) { - mDragScroller.stopScrolling(true); - destroyFloatView(); - clearPositions(); - adjustAllItems(); - - if (mInTouchEvent) { - mDragState = STOPPED; - } else { - mDragState = IDLE; - } - } - } - - private void clearPositions() { - mSrcPos = -1; - mFirstExpPos = -1; - mSecondExpPos = -1; - mFloatPos = -1; - } - - private void dropFloatView() { - // must set to avoid cancelDrag being called from the - // DataSetObserver - mDragState = DROPPING; - - if (mDropListener != null && mFloatPos >= 0 && mFloatPos < getCount()) { - final int numHeaders = getHeaderViewsCount(); - mDropListener.drop(mSrcPos - numHeaders, mFloatPos - numHeaders); - } - - destroyFloatView(); - - adjustOnReorder(); - clearPositions(); - adjustAllItems(); - - // now the drag is done - if (mInTouchEvent) { - mDragState = STOPPED; - } else { - mDragState = IDLE; - } - } - - private void doRemoveItem() { - doRemoveItem(mSrcPos - getHeaderViewsCount()); - } - - /** - * Removes dragged item from the list. Calls RemoveListener. - */ - private void doRemoveItem(int which) { - // must set to avoid cancelDrag being called from the - // DataSetObserver - mDragState = REMOVING; - - // end it - if (mRemoveListener != null) { - mRemoveListener.remove(which); - } - - destroyFloatView(); - - adjustOnReorder(); - clearPositions(); - - // now the drag is done - if (mInTouchEvent) { - mDragState = STOPPED; - } else { - mDragState = IDLE; - } - } - - private void adjustOnReorder() { - final int firstPos = getFirstVisiblePosition(); - // Log.d("mobeta", "first="+firstPos+" src="+mSrcPos); - if (mSrcPos < firstPos) { - // collapsed src item is off screen; - // adjust the scroll after item heights have been fixed - View v = getChildAt(0); - int top = 0; - if (v != null) { - top = v.getTop(); - } - // Log.d("mobeta", "top="+top+" fvh="+mFloatViewHeight); - setSelectionFromTop(firstPos - 1, top - getPaddingTop()); - } - } - - /** - * Stop a drag in progress. Pass true if you would like to - * remove the dragged item from the list. - * - * @param remove - * Remove the dragged item from the list. Calls a registered - * RemoveListener, if one exists. Otherwise, calls the - * DropListener, if one exists. - * - * @return True if the stop was successful. False if there is no floating - * View. - */ - public boolean stopDrag(boolean remove) { - mUseRemoveVelocity = false; - return stopDrag(remove, 0); - } - - public boolean stopDragWithVelocity(boolean remove, float velocityX) { - - mUseRemoveVelocity = true; - return stopDrag(remove, velocityX); - } - - public boolean stopDrag(boolean remove, float velocityX) { - if (mFloatView != null) { - mDragScroller.stopScrolling(true); - - if (remove) { - removeItem(mSrcPos - getHeaderViewsCount(), velocityX); - } else { - if (mDropAnimator != null) { - mDropAnimator.start(); - } else { - dropFloatView(); - } - } - - if (mTrackDragSort) { - mDragSortTracker.stopTracking(); - } - - return true; - } else { - // stop failed - return false; - } - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - if (mIgnoreTouchEvent) { - mIgnoreTouchEvent = false; - return false; - } - - if (!mDragEnabled) { - return super.onTouchEvent(ev); - } - - boolean more = false; - - boolean lastCallWasIntercept = mLastCallWasIntercept; - mLastCallWasIntercept = false; - - if (!lastCallWasIntercept) { - saveTouchCoords(ev); - } - - // if (mFloatView != null) { - if (mDragState == DRAGGING) { - onDragTouchEvent(ev); - more = true; // give us more! - } else { - // what if float view is null b/c we dropped in middle - // of drag touch event? - - // if (mDragState != STOPPED) { - if (mDragState == IDLE) { - if (super.onTouchEvent(ev)) { - more = true; - } - } - - int action = ev.getAction() & MotionEvent.ACTION_MASK; - - switch (action) { - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: - doActionUpOrCancel(); - break; - default: - if (more) { - mCancelMethod = ON_TOUCH_EVENT; - } - } - } - - return more; - } - - private void doActionUpOrCancel() { - mCancelMethod = NO_CANCEL; - mInTouchEvent = false; - if (mDragState == STOPPED) { - mDragState = IDLE; - } - mCurrFloatAlpha = mFloatAlpha; - mListViewIntercepted = false; - mChildHeightCache.clear(); - } - - private void saveTouchCoords(MotionEvent ev) { - int action = ev.getAction() & MotionEvent.ACTION_MASK; - if (action != MotionEvent.ACTION_DOWN) { - mLastX = mX; - mLastY = mY; - } - mX = (int) ev.getX(); - mY = (int) ev.getY(); - if (action == MotionEvent.ACTION_DOWN) { - mLastX = mX; - mLastY = mY; - } - mOffsetX = (int) ev.getRawX() - mX; - mOffsetY = (int) ev.getRawY() - mY; - } - - public boolean listViewIntercepted() { - return mListViewIntercepted; - } - - private boolean mListViewIntercepted = false; - - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - if (!mDragEnabled) { - return super.onInterceptTouchEvent(ev); - } - - saveTouchCoords(ev); - mLastCallWasIntercept = true; - - int action = ev.getAction() & MotionEvent.ACTION_MASK; - - if (action == MotionEvent.ACTION_DOWN) { - if (mDragState != IDLE) { - // intercept and ignore - mIgnoreTouchEvent = true; - return true; - } - mInTouchEvent = true; - } - - boolean intercept = false; - - // the following deals with calls to super.onInterceptTouchEvent - if (mFloatView != null) { - // super's touch event canceled in startDrag - intercept = true; - } else { - if (super.onInterceptTouchEvent(ev)) { - mListViewIntercepted = true; - intercept = true; - } - - switch (action) { - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: - doActionUpOrCancel(); - break; - default: - if (intercept) { - mCancelMethod = ON_TOUCH_EVENT; - } else { - mCancelMethod = ON_INTERCEPT_TOUCH_EVENT; - } - } - } - - if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { - mInTouchEvent = false; - } - - return intercept; - } - - /** - * Set the width of each drag scroll region by specifying a fraction of the - * ListView height. - * - * @param heightFraction - * Fraction of ListView height. Capped at 0.5f. - * - */ - public void setDragScrollStart(float heightFraction) { - setDragScrollStarts(heightFraction, heightFraction); - } - - /** - * Set the width of each drag scroll region by specifying a fraction of the - * ListView height. - * - * @param upperFrac - * Fraction of ListView height for up-scroll bound. Capped at - * 0.5f. - * @param lowerFrac - * Fraction of ListView height for down-scroll bound. Capped at - * 0.5f. - * - */ - public void setDragScrollStarts(float upperFrac, float lowerFrac) { - if (lowerFrac > 0.5f) { - mDragDownScrollStartFrac = 0.5f; - } else { - mDragDownScrollStartFrac = lowerFrac; - } - - if (upperFrac > 0.5f) { - mDragUpScrollStartFrac = 0.5f; - } else { - mDragUpScrollStartFrac = upperFrac; - } - - if (getHeight() != 0) { - updateScrollStarts(); - } - } - - private void continueDrag(int x, int y) { - - // proposed position - mFloatLoc.x = x - mDragDeltaX; - mFloatLoc.y = y - mDragDeltaY; - - doDragFloatView(true); - - int minY = Math.min(y, mFloatViewMid + mFloatViewHeightHalf); - int maxY = Math.max(y, mFloatViewMid - mFloatViewHeightHalf); - - // get the current scroll direction - int currentScrollDir = mDragScroller.getScrollDir(); - - if (minY > mLastY && minY > mDownScrollStartY && currentScrollDir != DragScroller.DOWN) { - // dragged down, it is below the down scroll start and it is not - // scrolling up - - if (currentScrollDir != DragScroller.STOP) { - // moved directly from up scroll to down scroll - mDragScroller.stopScrolling(true); - } - - // start scrolling down - mDragScroller.startScrolling(DragScroller.DOWN); - } else if (maxY < mLastY && maxY < mUpScrollStartY && currentScrollDir != DragScroller.UP) { - // dragged up, it is above the up scroll start and it is not - // scrolling up - - if (currentScrollDir != DragScroller.STOP) { - // moved directly from down scroll to up scroll - mDragScroller.stopScrolling(true); - } - - // start scrolling up - mDragScroller.startScrolling(DragScroller.UP); - } else if (maxY >= mUpScrollStartY && minY <= mDownScrollStartY && mDragScroller.isScrolling()) { - // not in the upper nor in the lower drag-scroll regions but it is - // still scrolling - - mDragScroller.stopScrolling(true); - } - } - - private void updateScrollStarts() { - final int padTop = getPaddingTop(); - final int listHeight = getHeight() - padTop - getPaddingBottom(); - float heightF = listHeight; - - mUpScrollStartYF = padTop + mDragUpScrollStartFrac * heightF; - mDownScrollStartYF = padTop + (1.0f - mDragDownScrollStartFrac) * heightF; - - mUpScrollStartY = (int) mUpScrollStartYF; - mDownScrollStartY = (int) mDownScrollStartYF; - - mDragUpScrollHeight = mUpScrollStartYF - padTop; - mDragDownScrollHeight = padTop + listHeight - mDownScrollStartYF; - } - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - updateScrollStarts(); - } - - private void adjustAllItems() { - final int first = getFirstVisiblePosition(); - final int last = getLastVisiblePosition(); - - int begin = Math.max(0, getHeaderViewsCount() - first); - int end = Math.min(last - first, getCount() - 1 - getFooterViewsCount() - first); - - for (int i = begin; i <= end; ++i) { - View v = getChildAt(i); - if (v != null) { - adjustItem(first + i, v, false); - } - } - } - - private void adjustItem(int position) { - View v = getChildAt(position - getFirstVisiblePosition()); - - if (v != null) { - adjustItem(position, v, false); - } - } - - /** - * Sets layout param height, gravity, and visibility on wrapped item. - */ - private void adjustItem(int position, View v, boolean invalidChildHeight) { - - // Adjust item height - ViewGroup.LayoutParams lp = v.getLayoutParams(); - int height; - if (position != mSrcPos && position != mFirstExpPos && position != mSecondExpPos) { - height = ViewGroup.LayoutParams.WRAP_CONTENT; - } else { - height = calcItemHeight(position, v, invalidChildHeight); - } - - if (height != lp.height) { - lp.height = height; - v.setLayoutParams(lp); - } - - // Adjust item gravity - if (position == mFirstExpPos || position == mSecondExpPos) { - if (position < mSrcPos) { - ((DragSortItemView) v).setGravity(Gravity.BOTTOM); - } else if (position > mSrcPos) { - ((DragSortItemView) v).setGravity(Gravity.TOP); - } - } - - // Finally adjust item visibility - - int oldVis = v.getVisibility(); - int vis = View.VISIBLE; - - if (position == mSrcPos && mFloatView != null) { - vis = View.INVISIBLE; - } - - if (vis != oldVis) { - v.setVisibility(vis); - } - } - - private int getChildHeight(int position) { - if (position == mSrcPos) { - return 0; - } - - View v = getChildAt(position - getFirstVisiblePosition()); - - if (v != null) { - // item is onscreen, therefore child height is valid, - // hence the "true" - return getChildHeight(position, v, false); - } else { - // item is offscreen - // first check cache for child height at this position - int childHeight = mChildHeightCache.get(position); - if (childHeight != -1) { - // Log.d("mobeta", "found child height in cache!"); - return childHeight; - } - - final ListAdapter adapter = getAdapter(); - int type = adapter.getItemViewType(position); - - // There might be a better place for checking for the following - final int typeCount = adapter.getViewTypeCount(); - if (typeCount != mSampleViewTypes.length) { - mSampleViewTypes = new View[typeCount]; - } - - if (type >= 0) { - if (mSampleViewTypes[type] == null) { - v = adapter.getView(position, null, this); - mSampleViewTypes[type] = v; - } else { - v = adapter.getView(position, mSampleViewTypes[type], this); - } - } else { - // type is HEADER_OR_FOOTER or IGNORE - v = adapter.getView(position, null, this); - } - - // current child height is invalid, hence "true" below - childHeight = getChildHeight(position, v, true); - - // cache it because this could have been expensive - mChildHeightCache.add(position, childHeight); - - return childHeight; - } - } - - private int getChildHeight(int position, View item, boolean invalidChildHeight) { - if (position == mSrcPos) { - return 0; - } - - View child; - if (position < getHeaderViewsCount() || position >= getCount() - getFooterViewsCount()) { - child = item; - } else { - child = ((ViewGroup) item).getChildAt(0); - } - - ViewGroup.LayoutParams lp = child.getLayoutParams(); - - if (lp != null) { - if (lp.height > 0) { - return lp.height; - } - } - - int childHeight = child.getHeight(); - - if (childHeight == 0 || invalidChildHeight) { - measureItem(child); - childHeight = child.getMeasuredHeight(); - } - - return childHeight; - } - - private int calcItemHeight(int position, View item, boolean invalidChildHeight) { - return calcItemHeight(position, getChildHeight(position, item, invalidChildHeight)); - } - - private int calcItemHeight(int position, int childHeight) { - - int divHeight = getDividerHeight(); - - boolean isSliding = mAnimate && mFirstExpPos != mSecondExpPos; - int maxNonSrcBlankHeight = mFloatViewHeight - mItemHeightCollapsed; - int slideHeight = (int) (mSlideFrac * maxNonSrcBlankHeight); - - int height; - - if (position == mSrcPos) { - if (mSrcPos == mFirstExpPos) { - if (isSliding) { - height = slideHeight + mItemHeightCollapsed; - } else { - height = mFloatViewHeight; - } - } else if (mSrcPos == mSecondExpPos) { - // if gets here, we know an item is sliding - height = mFloatViewHeight - slideHeight; - } else { - height = mItemHeightCollapsed; - } - } else if (position == mFirstExpPos) { - if (isSliding) { - height = childHeight + slideHeight; - } else { - height = childHeight + maxNonSrcBlankHeight; - } - } else if (position == mSecondExpPos) { - // we know an item is sliding (b/c 2ndPos != 1stPos) - height = childHeight + maxNonSrcBlankHeight - slideHeight; - } else { - height = childHeight; - } - - return height; - } - - @Override - public void requestLayout() { - if (!mBlockLayoutRequests) { - super.requestLayout(); - } - } - - private int adjustScroll(int movePos, View moveItem, int oldFirstExpPos, int oldSecondExpPos) { - int adjust = 0; - - final int childHeight = getChildHeight(movePos); - - int moveHeightBefore = moveItem.getHeight(); - int moveHeightAfter = calcItemHeight(movePos, childHeight); - - int moveBlankBefore = moveHeightBefore; - int moveBlankAfter = moveHeightAfter; - if (movePos != mSrcPos) { - moveBlankBefore -= childHeight; - moveBlankAfter -= childHeight; - } - - int maxBlank = mFloatViewHeight; - if (mSrcPos != mFirstExpPos && mSrcPos != mSecondExpPos) { - maxBlank -= mItemHeightCollapsed; - } - - if (movePos <= oldFirstExpPos) { - if (movePos > mFirstExpPos) { - adjust += maxBlank - moveBlankAfter; - } - } else if (movePos == oldSecondExpPos) { - if (movePos <= mFirstExpPos) { - adjust += moveBlankBefore - maxBlank; - } else if (movePos == mSecondExpPos) { - adjust += moveHeightBefore - moveHeightAfter; - } else { - adjust += moveBlankBefore; - } - } else { - if (movePos <= mFirstExpPos) { - adjust -= maxBlank; - } else if (movePos == mSecondExpPos) { - adjust -= moveBlankAfter; - } - } - - return adjust; - } - - private void measureItem(View item) { - ViewGroup.LayoutParams lp = item.getLayoutParams(); - if (lp == null) { - lp = new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); - item.setLayoutParams(lp); - } - int wspec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec, getListPaddingLeft() + getListPaddingRight(), - lp.width); - int hspec; - if (lp.height > 0) { - hspec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY); - } else { - hspec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); - } - item.measure(wspec, hspec); - } - - private void measureFloatView() { - if (mFloatView != null) { - measureItem(mFloatView); - mFloatViewHeight = mFloatView.getMeasuredHeight(); - mFloatViewHeightHalf = mFloatViewHeight / 2; - } - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - // Log.d("mobeta", "onMeasure called"); - if (mFloatView != null) { - if (mFloatView.isLayoutRequested()) { - measureFloatView(); - } - mFloatViewOnMeasured = true; // set to false after layout - } - mWidthMeasureSpec = widthMeasureSpec; - } - - @Override - protected void layoutChildren() { - super.layoutChildren(); - - if (mFloatView != null) { - if (mFloatView.isLayoutRequested() && !mFloatViewOnMeasured) { - // Have to measure here when usual android measure - // pass is skipped. This happens during a drag-sort - // when layoutChildren is called directly. - measureFloatView(); - } - mFloatView.layout(0, 0, mFloatView.getMeasuredWidth(), mFloatView.getMeasuredHeight()); - mFloatViewOnMeasured = false; - } - } - - protected boolean onDragTouchEvent(MotionEvent ev) { - // we are in a drag - int action = ev.getAction() & MotionEvent.ACTION_MASK; - - switch (ev.getAction() & MotionEvent.ACTION_MASK) { - case MotionEvent.ACTION_CANCEL: - if (mDragState == DRAGGING) { - cancelDrag(); - } - doActionUpOrCancel(); - break; - case MotionEvent.ACTION_UP: - // Log.d("mobeta", "calling stopDrag from onDragTouchEvent"); - if (mDragState == DRAGGING) { - stopDrag(false); - } - doActionUpOrCancel(); - break; - case MotionEvent.ACTION_MOVE: - continueDrag((int) ev.getX(), (int) ev.getY()); - break; - } - - return true; - } - - private boolean mFloatViewInvalidated = false; - - private void invalidateFloatView() { - mFloatViewInvalidated = true; - } - - /** - * Start a drag of item at position using the registered - * FloatViewManager. Calls through to - * {@link #startDrag(int,View,int,int,int)} after obtaining the floating - * View from the FloatViewManager. - * - * @param position - * Item to drag. - * @param dragFlags - * Flags that restrict some movements of the floating View. For - * example, set dragFlags |= - * ~{@link #DRAG_NEG_X} to allow dragging the floating View in all - * directions except off the screen to the left. - * @param deltaX - * Offset in x of the touch coordinate from the left edge of the - * floating View (i.e. touch-x minus float View left). - * @param deltaY - * Offset in y of the touch coordinate from the top edge of the - * floating View (i.e. touch-y minus float View top). - * - * @return True if the drag was started, false otherwise. This - * startDrag will fail if we are not currently in a - * touch event, there is no registered FloatViewManager, or the - * FloatViewManager returns a null View. - */ - public boolean startDrag(int position, int dragFlags, int deltaX, int deltaY) { - if (!mInTouchEvent || mFloatViewManager == null) { - return false; - } - - View v = mFloatViewManager.onCreateFloatView(position); - - if (v == null) { - return false; - } else { - return startDrag(position, v, dragFlags, deltaX, deltaY); - } - - } - - /** - * Start a drag of item at position without using a - * FloatViewManager. - * - * @param position - * Item to drag. - * @param floatView - * Floating View. - * @param dragFlags - * Flags that restrict some movements of the floating View. For - * example, set dragFlags |= - * ~{@link #DRAG_NEG_X} to allow dragging the floating View in all - * directions except off the screen to the left. - * @param deltaX - * Offset in x of the touch coordinate from the left edge of the - * floating View (i.e. touch-x minus float View left). - * @param deltaY - * Offset in y of the touch coordinate from the top edge of the - * floating View (i.e. touch-y minus float View top). - * - * @return True if the drag was started, false otherwise. This - * startDrag will fail if we are not currently in a - * touch event, floatView is null, or there is a drag - * in progress. - */ - public boolean startDrag(int position, View floatView, int dragFlags, int deltaX, int deltaY) { - if (mDragState != IDLE || !mInTouchEvent || mFloatView != null || floatView == null || !mDragEnabled) { - return false; - } - - if (getParent() != null) { - getParent().requestDisallowInterceptTouchEvent(true); - } - - int pos = position + getHeaderViewsCount(); - mFirstExpPos = pos; - mSecondExpPos = pos; - mSrcPos = pos; - mFloatPos = pos; - - // mDragState = dragType; - mDragState = DRAGGING; - mDragFlags = 0; - mDragFlags |= dragFlags; - - mFloatView = floatView; - measureFloatView(); // sets mFloatViewHeight - - mDragDeltaX = deltaX; - mDragDeltaY = deltaY; - mDragStartY = mY; - - // updateFloatView(mX - mDragDeltaX, mY - mDragDeltaY); - mFloatLoc.x = mX - mDragDeltaX; - mFloatLoc.y = mY - mDragDeltaY; - - // set src item invisible - final View srcItem = getChildAt(mSrcPos - getFirstVisiblePosition()); - - if (srcItem != null) { - srcItem.setVisibility(View.INVISIBLE); - } - - if (mTrackDragSort) { - mDragSortTracker.startTracking(); - } - - // once float view is created, events are no longer passed - // to ListView - switch (mCancelMethod) { - case ON_TOUCH_EVENT: - super.onTouchEvent(mCancelEvent); - break; - case ON_INTERCEPT_TOUCH_EVENT: - super.onInterceptTouchEvent(mCancelEvent); - break; - } - - requestLayout(); - - if (mLiftAnimator != null) { - mLiftAnimator.start(); - } - - return true; - } - - private void doDragFloatView(boolean forceInvalidate) { - int movePos = getFirstVisiblePosition() + getChildCount() / 2; - View moveItem = getChildAt(getChildCount() / 2); - - if (moveItem == null) { - return; - } - - doDragFloatView(movePos, moveItem, forceInvalidate); - } - - private void doDragFloatView(int movePos, View moveItem, boolean forceInvalidate) { - mBlockLayoutRequests = true; - - updateFloatView(); - - int oldFirstExpPos = mFirstExpPos; - int oldSecondExpPos = mSecondExpPos; - - boolean updated = updatePositions(); - - if (updated) { - adjustAllItems(); - int scroll = adjustScroll(movePos, moveItem, oldFirstExpPos, oldSecondExpPos); - // Log.d("mobeta", " adjust scroll="+scroll); - - setSelectionFromTop(movePos, moveItem.getTop() + scroll - getPaddingTop()); - layoutChildren(); - } - - if (updated || forceInvalidate) { - invalidate(); - } - - mBlockLayoutRequests = false; - } - - /** - * Sets float View location based on suggested values and constraints set in - * mDragFlags. - */ - private void updateFloatView() { - - if (mFloatViewManager != null) { - mTouchLoc.set(mX, mY); - mFloatViewManager.onDragFloatView(mFloatView, mFloatLoc, mTouchLoc); - } - - final int floatX = mFloatLoc.x; - final int floatY = mFloatLoc.y; - - // restrict x motion - int padLeft = getPaddingLeft(); - if ((mDragFlags & DRAG_POS_X) == 0 && floatX > padLeft) { - mFloatLoc.x = padLeft; - } else if ((mDragFlags & DRAG_NEG_X) == 0 && floatX < padLeft) { - mFloatLoc.x = padLeft; - } - - // keep floating view from going past bottom of last header view - final int numHeaders = getHeaderViewsCount(); - final int numFooters = getFooterViewsCount(); - final int firstPos = getFirstVisiblePosition(); - final int lastPos = getLastVisiblePosition(); - - // Log.d("mobeta", - // "nHead="+numHeaders+" nFoot="+numFooters+" first="+firstPos+" last="+lastPos); - int topLimit = getPaddingTop(); - if (firstPos < numHeaders) { - topLimit = getChildAt(numHeaders - firstPos - 1).getBottom(); - } - if ((mDragFlags & DRAG_NEG_Y) == 0) { - if (firstPos <= mSrcPos) { - topLimit = Math.max(getChildAt(mSrcPos - firstPos).getTop(), topLimit); - } - } - // bottom limit is top of first footer View or - // bottom of last item in list - int bottomLimit = getHeight() - getPaddingBottom(); - if (lastPos >= getCount() - numFooters - 1) { - bottomLimit = getChildAt(getCount() - numFooters - 1 - firstPos).getBottom(); - } - if ((mDragFlags & DRAG_POS_Y) == 0) { - if (lastPos >= mSrcPos) { - bottomLimit = Math.min(getChildAt(mSrcPos - firstPos).getBottom(), bottomLimit); - } - } - - // Log.d("mobeta", "dragView top=" + (y - mDragDeltaY)); - // Log.d("mobeta", "limit=" + limit); - // Log.d("mobeta", "mDragDeltaY=" + mDragDeltaY); - - if (floatY < topLimit) { - mFloatLoc.y = topLimit; - } else if (floatY + mFloatViewHeight > bottomLimit) { - mFloatLoc.y = bottomLimit - mFloatViewHeight; - } - - // get y-midpoint of floating view (constrained to ListView bounds) - mFloatViewMid = mFloatLoc.y + mFloatViewHeightHalf; - } - - private void destroyFloatView() { - if (mFloatView != null) { - mFloatView.setVisibility(GONE); - if (mFloatViewManager != null) { - mFloatViewManager.onDestroyFloatView(mFloatView); - } - mFloatView = null; - invalidate(); - } - } - - /** - * Interface for customization of the floating View appearance and dragging - * behavior. Implement your own and pass it to {@link #setFloatViewManager}. - * If your own is not passed, the default {@link SimpleFloatViewManager} - * implementation is used. - */ - public interface FloatViewManager { - /** - * Return the floating View for item at position. - * DragSortListView will measure and layout this View for you, so feel - * free to just inflate it. You can help DSLV by setting some - * {@link ViewGroup.LayoutParams} on this View; otherwise it will set - * some for you (with a width of FILL_PARENT and a height of - * WRAP_CONTENT). - * - * @param position - * Position of item to drag (NOTE: position - * excludes header Views; thus, if you want to call - * {@link ListView#getChildAt(int)}, you will need to add - * {@link ListView#getHeaderViewsCount()} to the index). - * - * @return The View you wish to display as the floating View. - */ - public View onCreateFloatView(int position); - - /** - * Called whenever the floating View is dragged. Float View properties - * can be changed here. Also, the upcoming location of the float View - * can be altered by setting location.x and - * location.y. - * - * @param floatView - * The floating View. - * @param location - * The location (top-left; relative to DSLV top-left) at - * which the float View would like to appear, given the - * current touch location and the offset provided in - * {@link DragSortListView#startDrag}. - * @param touch - * The current touch location (relative to DSLV top-left). - * @param pendingScroll - */ - public void onDragFloatView(View floatView, Point location, Point touch); - - /** - * Called when the float View is dropped; lets you perform any necessary - * cleanup. The internal DSLV floating View reference is set to null - * immediately after this is called. - * - * @param floatView - * The floating View passed to - * {@link #onCreateFloatView(int)}. - */ - public void onDestroyFloatView(View floatView); - } - - public void setFloatViewManager(FloatViewManager manager) { - mFloatViewManager = manager; - } - - public void setDragListener(DragListener l) { - mDragListener = l; - } - - /** - * Allows for easy toggling between a DragSortListView and a regular old - * ListView. If enabled, items are draggable, where the drag init mode - * determines how items are lifted (see {@link setDragInitMode(int)}). If - * disabled, items cannot be dragged. - * - * @param enabled - * Set true to enable list item dragging - */ - public void setDragEnabled(boolean enabled) { - mDragEnabled = enabled; - } - - public boolean isDragEnabled() { - return mDragEnabled; - } - - /** - * This better reorder your ListAdapter! DragSortListView does not do this - * for you; doesn't make sense to. Make sure - * {@link BaseAdapter#notifyDataSetChanged()} or something like it is called - * in your implementation. Furthermore, if you have a choiceMode other than - * none and the ListAdapter does not return true for - * {@link ListAdapter#hasStableIds()}, you will need to call - * {@link #moveCheckState(int, int)} to move the check boxes along with the - * list items. - * - * @param l - */ - public void setDropListener(DropListener l) { - mDropListener = l; - } - - /** - * Probably a no-brainer, but make sure that your remove listener calls - * {@link BaseAdapter#notifyDataSetChanged()} or something like it. When an - * item removal occurs, DragSortListView relies on a redraw of all the items - * to recover invisible views and such. Strictly speaking, if you remove - * something, your dataset has changed... - * - * @param l - */ - public void setRemoveListener(RemoveListener l) { - mRemoveListener = l; - } - - public interface DragListener { - public void drag(int from, int to); - } - - /** - * Your implementation of this has to reorder your ListAdapter! Make sure to - * call {@link BaseAdapter#notifyDataSetChanged()} or something like it in - * your implementation. - * - * @author heycosmo - * - */ - public interface DropListener { - public void drop(int from, int to); - } - - /** - * Make sure to call {@link BaseAdapter#notifyDataSetChanged()} or something - * like it in your implementation. - * - * @author heycosmo - * - */ - public interface RemoveListener { - public void remove(int which); - } - - public interface DragSortListener extends DropListener, DragListener, RemoveListener { - } - - public void setDragSortListener(DragSortListener l) { - setDropListener(l); - setDragListener(l); - setRemoveListener(l); - } - - /** - * Completely custom scroll speed profile. Default increases linearly with - * position and is constant in time. Create your own by implementing - * {@link DragSortListView.DragScrollProfile}. - * - * @param ssp - */ - public void setDragScrollProfile(DragScrollProfile ssp) { - if (ssp != null) { - mScrollProfile = ssp; - } - } - - /** - * Use this to move the check state of an item from one position to another - * in a drop operation. If you have a choiceMode which is not none, this - * method must be called when the order of items changes in an underlying - * adapter which does not have stable IDs (see - * {@link ListAdapter#hasStableIds()}). This is because without IDs, the - * ListView has no way of knowing which items have moved where, and cannot - * update the check state accordingly. - *

- * A word of warning about a "feature" in Android that you may run into when - * dealing with movable list items: for an adapter that does have - * stable IDs, ListView will attempt to locate each item based on its ID and - * move the check state from the item's old position to the new position — - * which is all fine and good (and removes the need for calling this - * function), except for the half-baked approach. Apparently to save time in - * the naive algorithm used, ListView will only search for an ID in the - * close neighborhood of the old position. If the user moves an item too far - * (specifically, more than 20 rows away), ListView will give up and just - * force the item to be unchecked. So if there is a reasonable chance that - * the user will move items more than 20 rows away from the original - * position, you may wish to use an adapter with unstable IDs and call this - * method manually instead. - * - * @param from - * @param to - */ - public void moveCheckState(int from, int to) { - // This method runs in O(n log n) time (n being the number of list - // items). The bottleneck is the call to AbsListView.setItemChecked, - // which is O(log n) because of the binary search involved in calling - // SparseBooleanArray.put(). - // - // To improve on the average time, we minimize the number of calls to - // setItemChecked by only calling it for items that actually have a - // changed state. This is achieved by building a list containing the - // start and end of the "runs" of checked items, and then moving the - // runs. Note that moving an item from A to B is essentially a rotation - // of the range of items in [A, B]. Let's say we have - // . . U V X Y Z . . - // and move U after Z. This is equivalent to a rotation one step to the - // left within the range you are moving across: - // . . V X Y Z U . . - // - // So, to perform the move we enumerate all the runs within the move - // range, then rotate each run one step to the left or right (depending - // on move direction). For example, in the list: - // X X . X X X . X - // we have two runs. One begins at the last item of the list and wraps - // around to the beginning, ending at position 1. The second begins at - // position 3 and ends at position 5. To rotate a run, regardless of - // length, we only need to set a check mark at one end of the run, and - // clear a check mark at the other end: - // X . X X X . X X - SparseBooleanArray cip = getCheckedItemPositions(); - int rangeStart = from; - int rangeEnd = to; - if (to < from) { - rangeStart = to; - rangeEnd = from; - } - rangeEnd += 1; - - int[] runStart = new int[cip.size()]; - int[] runEnd = new int[cip.size()]; - int runCount = buildRunList(cip, rangeStart, rangeEnd, runStart, runEnd); - if (runCount == 1 && (runStart[0] == runEnd[0])) { - // Special case where all items are checked, we can never set any - // item to false like we do below. - return; - } - - if (from < to) { - for (int i = 0; i != runCount; i++) { - setItemChecked(rotate(runStart[i], -1, rangeStart, rangeEnd), true); - setItemChecked(rotate(runEnd[i], -1, rangeStart, rangeEnd), false); - } - - } else { - for (int i = 0; i != runCount; i++) { - setItemChecked(runStart[i], false); - setItemChecked(runEnd[i], true); - } - } - } - - /** - * Use this when an item has been deleted, to move the check state of all - * following items up one step. If you have a choiceMode which is not none, - * this method must be called when the order of items changes in an - * underlying adapter which does not have stable IDs (see - * {@link ListAdapter#hasStableIds()}). This is because without IDs, the - * ListView has no way of knowing which items have moved where, and cannot - * update the check state accordingly. - * - * See also further comments on {@link #moveCheckState(int, int)}. - * - * @param position - */ - public void removeCheckState(int position) { - SparseBooleanArray cip = getCheckedItemPositions(); - - if (cip.size() == 0) - return; - int[] runStart = new int[cip.size()]; - int[] runEnd = new int[cip.size()]; - int rangeStart = position; - int rangeEnd = cip.keyAt(cip.size() - 1) + 1; - int runCount = buildRunList(cip, rangeStart, rangeEnd, runStart, runEnd); - for (int i = 0; i != runCount; i++) { - if (!(runStart[i] == position || (runEnd[i] < runStart[i] && runEnd[i] > position))) { - // Only set a new check mark in front of this run if it does - // not contain the deleted position. If it does, we only need - // to make it one check mark shorter at the end. - setItemChecked(rotate(runStart[i], -1, rangeStart, rangeEnd), true); - } - setItemChecked(rotate(runEnd[i], -1, rangeStart, rangeEnd), false); - } - } - - private static int buildRunList(SparseBooleanArray cip, int rangeStart, int rangeEnd, int[] runStart, int[] runEnd) { - int runCount = 0; - - int i = findFirstSetIndex(cip, rangeStart, rangeEnd); - if (i == -1) - return 0; - - int position = cip.keyAt(i); - int currentRunStart = position; - int currentRunEnd = currentRunStart + 1; - for (i++; i < cip.size() && (position = cip.keyAt(i)) < rangeEnd; i++) { - if (!cip.valueAt(i)) // not checked => not interesting - continue; - if (position == currentRunEnd) { - currentRunEnd++; - } else { - runStart[runCount] = currentRunStart; - runEnd[runCount] = currentRunEnd; - runCount++; - currentRunStart = position; - currentRunEnd = position + 1; - } - } - - if (currentRunEnd == rangeEnd) { - // rangeStart and rangeEnd are equivalent positions so to be - // consistent we translate them to the same integer value. That way - // we can check whether a run covers the entire range by just - // checking if the start equals the end position. - currentRunEnd = rangeStart; - } - runStart[runCount] = currentRunStart; - runEnd[runCount] = currentRunEnd; - runCount++; - - if (runCount > 1) { - if (runStart[0] == rangeStart && runEnd[runCount - 1] == rangeStart) { - // The last run ends at the end of the range, and the first run - // starts at the beginning of the range. So they are actually - // part of the same run, except they wrap around the end of the - // range. To avoid adjacent runs, we need to merge them. - runStart[0] = runStart[runCount - 1]; - runCount--; - } - } - return runCount; - } - - private static int rotate(int value, int offset, int lowerBound, int upperBound) { - int windowSize = upperBound - lowerBound; - - value += offset; - if (value < lowerBound) { - value += windowSize; - } else if (value >= upperBound) { - value -= windowSize; - } - return value; - } - - private static int findFirstSetIndex(SparseBooleanArray sba, int rangeStart, int rangeEnd) { - int size = sba.size(); - int i = insertionIndexForKey(sba, rangeStart); - while (i < size && sba.keyAt(i) < rangeEnd && !sba.valueAt(i)) - i++; - if (i == size || sba.keyAt(i) >= rangeEnd) - return -1; - return i; - } - - private static int insertionIndexForKey(SparseBooleanArray sba, int key) { - int low = 0; - int high = sba.size(); - while (high - low > 0) { - int middle = (low + high) >> 1; - if (sba.keyAt(middle) < key) - low = middle + 1; - else - high = middle; - } - return low; - } - - /** - * Interface for controlling scroll speed as a function of touch position - * and time. Use - * {@link DragSortListView#setDragScrollProfile(DragScrollProfile)} to set - * custom profile. - * - * @author heycosmo - * - */ - public interface DragScrollProfile { - /** - * Return a scroll speed in pixels/millisecond. Always return a positive - * number. - * - * @param w - * Normalized position in scroll region (i.e. w \in [0,1]). - * Small w typically means slow scrolling. - * @param t - * Time (in milliseconds) since start of scroll (handy if you - * want scroll acceleration). - * @return Scroll speed at position w and time t in pixels/ms. - */ - float getSpeed(float w, long t); - } - - private class DragScroller implements Runnable { - - private boolean mAbort; - - private long mPrevTime; - private long mCurrTime; - - private int dy; - private float dt; - private long tStart; - private int scrollDir; - - public final static int STOP = -1; - public final static int UP = 0; - public final static int DOWN = 1; - - private float mScrollSpeed; // pixels per ms - - private boolean mScrolling = false; - - private int mLastHeader; - private int mFirstFooter; - - public boolean isScrolling() { - return mScrolling; - } - - public int getScrollDir() { - return mScrolling ? scrollDir : STOP; - } - - public DragScroller() { - } - - public void startScrolling(int dir) { - if (!mScrolling) { - // Debug.startMethodTracing("dslv-scroll"); - mAbort = false; - mScrolling = true; - tStart = SystemClock.uptimeMillis(); - mPrevTime = tStart; - scrollDir = dir; - post(this); - } - } - - public void stopScrolling(boolean now) { - if (now) { - removeCallbacks(this); - mScrolling = false; - } else { - mAbort = true; - } - - // Debug.stopMethodTracing(); - } - - @Override - public void run() { - if (mAbort) { - mScrolling = false; - return; - } - - // Log.d("mobeta", "scroll"); - - final int first = getFirstVisiblePosition(); - final int last = getLastVisiblePosition(); - final int count = getCount(); - final int padTop = getPaddingTop(); - final int listHeight = getHeight() - padTop - getPaddingBottom(); - - int minY = Math.min(mY, mFloatViewMid + mFloatViewHeightHalf); - int maxY = Math.max(mY, mFloatViewMid - mFloatViewHeightHalf); - - if (scrollDir == UP) { - View v = getChildAt(0); - // Log.d("mobeta", "vtop="+v.getTop()+" padtop="+padTop); - if (v == null) { - mScrolling = false; - return; - } else { - if (first == 0 && v.getTop() == padTop) { - mScrolling = false; - return; - } - } - mScrollSpeed = mScrollProfile.getSpeed((mUpScrollStartYF - maxY) / mDragUpScrollHeight, mPrevTime); - } else { - View v = getChildAt(last - first); - if (v == null) { - mScrolling = false; - return; - } else { - if (last == count - 1 && v.getBottom() <= listHeight + padTop) { - mScrolling = false; - return; - } - } - mScrollSpeed = -mScrollProfile.getSpeed((minY - mDownScrollStartYF) / mDragDownScrollHeight, mPrevTime); - } - - mCurrTime = SystemClock.uptimeMillis(); - dt = mCurrTime - mPrevTime; - - // dy is change in View position of a list item; i.e. positive dy - // means user is scrolling up (list item moves down the screen, - // remember - // y=0 is at top of View). - dy = Math.round(mScrollSpeed * dt); - - int movePos; - if (dy >= 0) { - dy = Math.min(listHeight, dy); - movePos = first; - } else { - dy = Math.max(-listHeight, dy); - movePos = last; - } - - final View moveItem = getChildAt(movePos - first); - int top = moveItem.getTop() + dy; - - if (movePos == 0 && top > padTop) { - top = padTop; - } - - // always do scroll - mBlockLayoutRequests = true; - - setSelectionFromTop(movePos, top - padTop); - layoutChildren(); - invalidate(); - - mBlockLayoutRequests = false; - - // scroll means relative float View movement - doDragFloatView(movePos, moveItem, false); - - mPrevTime = mCurrTime; - // Log.d("mobeta", " updated prevTime="+mPrevTime); - - post(this); - } - } - - private class DragSortTracker { - StringBuilder mBuilder = new StringBuilder(); - - File mFile; - - private int mNumInBuffer = 0; - private int mNumFlushes = 0; - - private boolean mTracking = false; - - public DragSortTracker() { - File root = Environment.getExternalStorageDirectory(); - mFile = new File(root, "dslv_state.txt"); - - if (!mFile.exists()) { - try { - mFile.createNewFile(); - Log.d("mobeta", "file created"); - } catch (IOException e) { - Log.w("mobeta", "Could not create dslv_state.txt"); - Log.d("mobeta", e.getMessage()); - } - } - - } - - public void startTracking() { - mBuilder.append("\n"); - mNumFlushes = 0; - mTracking = true; - } - - public void appendState() { - if (!mTracking) { - return; - } - - mBuilder.append("\n"); - final int children = getChildCount(); - final int first = getFirstVisiblePosition(); - mBuilder.append(" "); - for (int i = 0; i < children; ++i) { - mBuilder.append(first + i).append(","); - } - mBuilder.append("\n"); - - mBuilder.append(" "); - for (int i = 0; i < children; ++i) { - mBuilder.append(getChildAt(i).getTop()).append(","); - } - mBuilder.append("\n"); - mBuilder.append(" "); - for (int i = 0; i < children; ++i) { - mBuilder.append(getChildAt(i).getBottom()).append(","); - } - mBuilder.append("\n"); - - mBuilder.append(" ").append(mFirstExpPos).append("\n"); - mBuilder.append(" ") - .append(getItemHeight(mFirstExpPos) - getChildHeight(mFirstExpPos)) - .append("\n"); - mBuilder.append(" ").append(mSecondExpPos).append("\n"); - mBuilder.append(" ") - .append(getItemHeight(mSecondExpPos) - getChildHeight(mSecondExpPos)) - .append("\n"); - mBuilder.append(" ").append(mSrcPos).append("\n"); - mBuilder.append(" ").append(mFloatViewHeight + getDividerHeight()).append("\n"); - mBuilder.append(" ").append(getHeight()).append("\n"); - mBuilder.append(" ").append(mLastY).append("\n"); - mBuilder.append(" ").append(mFloatViewMid).append("\n"); - mBuilder.append(" "); - for (int i = 0; i < children; ++i) { - mBuilder.append(getShuffleEdge(first + i, getChildAt(i).getTop())).append(","); - } - mBuilder.append("\n"); - - mBuilder.append("\n"); - mNumInBuffer++; - - if (mNumInBuffer > 1000) { - flush(); - mNumInBuffer = 0; - } - } - - public void flush() { - if (!mTracking) { - return; - } - - // save to file on sdcard - try { - boolean append = true; - if (mNumFlushes == 0) { - append = false; - } - FileWriter writer = new FileWriter(mFile, append); - - writer.write(mBuilder.toString()); - mBuilder.delete(0, mBuilder.length()); - - writer.flush(); - writer.close(); - - mNumFlushes++; - } catch (IOException e) { - // do nothing - } - } - - public void stopTracking() { - if (mTracking) { - mBuilder.append("\n"); - flush(); - mTracking = false; - } - } - - } - -} diff --git a/Clover/app/src/main/java/com/mobeta/android/dslv/ResourceDragSortCursorAdapter.java b/Clover/app/src/main/java/com/mobeta/android/dslv/ResourceDragSortCursorAdapter.java deleted file mode 100644 index 63fc5c5a..00000000 --- a/Clover/app/src/main/java/com/mobeta/android/dslv/ResourceDragSortCursorAdapter.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * 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.mobeta.android.dslv; - -import android.content.Context; -import android.database.Cursor; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -// taken from v4 rev. 10 ResourceCursorAdapter.java - -/** - * Static library support version of the framework's - * {@link android.widget.ResourceCursorAdapter}. Used to write apps that run on - * platforms prior to Android 3.0. When running on Android 3.0 or above, this - * implementation is still used; it does not try to switch to the framework's - * implementation. See the framework SDK documentation for a class overview. - */ -public abstract class ResourceDragSortCursorAdapter extends DragSortCursorAdapter { - private int mLayout; - - private int mDropDownLayout; - - private LayoutInflater mInflater; - - /** - * Constructor the enables auto-requery. - * - * @deprecated This option is discouraged, as it results in Cursor queries - * being performed on the application's UI thread and thus can - * cause poor responsiveness or even Application Not Responding - * errors. As an alternative, use - * {@link android.app.LoaderManager} with a - * {@link android.content.CursorLoader}. - * - * @param context - * The context where the ListView associated with this adapter is - * running - * @param layout - * resource identifier of a layout file that defines the views - * for this list item. Unless you override them later, this will - * define both the item views and the drop down views. - */ - @Deprecated - public ResourceDragSortCursorAdapter(Context context, int layout, Cursor c) { - super(context, c); - mLayout = mDropDownLayout = layout; - mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - } - - /** - * Constructor with default behavior as per - * {@link CursorAdapter#CursorAdapter(Context, Cursor, boolean)}; it is - * recommended you not use this, but instead - * {@link #ResourceCursorAdapter(Context, int, Cursor, int)}. When using - * this constructor, {@link #FLAG_REGISTER_CONTENT_OBSERVER} will always be - * set. - * - * @param context - * The context where the ListView associated with this adapter is - * running - * @param layout - * resource identifier of a layout file that defines the views - * for this list item. Unless you override them later, this will - * define both the item views and the drop down views. - * @param c - * The cursor from which to get the data. - * @param autoRequery - * If true the adapter will call requery() on the cursor whenever - * it changes so the most recent data is always displayed. Using - * true here is discouraged. - */ - public ResourceDragSortCursorAdapter(Context context, int layout, Cursor c, boolean autoRequery) { - super(context, c, autoRequery); - mLayout = mDropDownLayout = layout; - mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - } - - /** - * Standard constructor. - * - * @param context - * The context where the ListView associated with this adapter is - * running - * @param layout - * Resource identifier of a layout file that defines the views - * for this list item. Unless you override them later, this will - * define both the item views and the drop down views. - * @param c - * The cursor from which to get the data. - * @param flags - * Flags used to determine the behavior of the adapter, as per - * {@link CursorAdapter#CursorAdapter(Context, Cursor, int)}. - */ - public ResourceDragSortCursorAdapter(Context context, int layout, Cursor c, int flags) { - super(context, c, flags); - mLayout = mDropDownLayout = layout; - mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - } - - /** - * Inflates view(s) from the specified XML file. - * - * @see android.widget.CursorAdapter#newView(android.content.Context, - * android.database.Cursor, ViewGroup) - */ - @Override - public View newView(Context context, Cursor cursor, ViewGroup parent) { - return mInflater.inflate(mLayout, parent, false); - } - - @Override - public View newDropDownView(Context context, Cursor cursor, ViewGroup parent) { - return mInflater.inflate(mDropDownLayout, parent, false); - } - - /** - *

- * Sets the layout resource of the item views. - *

- * - * @param layout - * the layout resources used to create item views - */ - public void setViewResource(int layout) { - mLayout = layout; - } - - /** - *

- * Sets the layout resource of the drop down views. - *

- * - * @param dropDownLayout - * the layout resources used to create drop down views - */ - public void setDropDownViewResource(int dropDownLayout) { - mDropDownLayout = dropDownLayout; - } -} diff --git a/Clover/app/src/main/java/com/mobeta/android/dslv/SimpleDragSortCursorAdapter.java b/Clover/app/src/main/java/com/mobeta/android/dslv/SimpleDragSortCursorAdapter.java deleted file mode 100644 index c01ecb61..00000000 --- a/Clover/app/src/main/java/com/mobeta/android/dslv/SimpleDragSortCursorAdapter.java +++ /dev/null @@ -1,448 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * 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.mobeta.android.dslv; - -import android.content.Context; -import android.database.Cursor; -import android.net.Uri; -import android.view.View; -import android.widget.ImageView; -import android.widget.TextView; - -// taken from sdk/sources/android-16/android/widget/SimpleCursorAdapter.java - -/** - * An easy adapter to map columns from a cursor to TextViews or ImageViews - * defined in an XML file. You can specify which columns you want, which views - * you want to display the columns, and the XML file that defines the appearance - * of these views. - * - * Binding occurs in two phases. First, if a - * {@link android.widget.SimpleCursorAdapter.ViewBinder} is available, - * {@link ViewBinder#setViewValue(android.view.View, android.database.Cursor, int)} - * is invoked. If the returned value is true, binding has occured. If the - * returned value is false and the view to bind is a TextView, - * {@link #setViewText(TextView, String)} is invoked. If the returned value is - * false and the view to bind is an ImageView, - * {@link #setViewImage(ImageView, String)} is invoked. If no appropriate - * binding can be found, an {@link IllegalStateException} is thrown. - * - * If this adapter is used with filtering, for instance in an - * {@link android.widget.AutoCompleteTextView}, you can use the - * {@link android.widget.SimpleCursorAdapter.CursorToStringConverter} and the - * {@link android.widget.FilterQueryProvider} interfaces to get control over the - * filtering process. You can refer to - * {@link #convertToString(android.database.Cursor)} and - * {@link #runQueryOnBackgroundThread(CharSequence)} for more information. - */ -public class SimpleDragSortCursorAdapter extends ResourceDragSortCursorAdapter { - /** - * A list of columns containing the data to bind to the UI. This field - * should be made private, so it is hidden from the SDK. {@hide} - */ - protected int[] mFrom; - /** - * A list of View ids representing the views to which the data must be - * bound. This field should be made private, so it is hidden from the SDK. - * {@hide} - */ - protected int[] mTo; - - private int mStringConversionColumn = -1; - private CursorToStringConverter mCursorToStringConverter; - private ViewBinder mViewBinder; - - String[] mOriginalFrom; - - /** - * Constructor the enables auto-requery. - * - * @deprecated This option is discouraged, as it results in Cursor queries - * being performed on the application's UI thread and thus can - * cause poor responsiveness or even Application Not Responding - * errors. As an alternative, use - * {@link android.app.LoaderManager} with a - * {@link android.content.CursorLoader}. - */ - @Deprecated - public SimpleDragSortCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to) { - super(context, layout, c); - mTo = to; - mOriginalFrom = from; - findColumns(c, from); - } - - /** - * Standard constructor. - * - * @param context - * The context where the ListView associated with this - * SimpleListItemFactory is running - * @param layout - * resource identifier of a layout file that defines the views - * for this list item. The layout file should include at least - * those named views defined in "to" - * @param c - * The database cursor. Can be null if the cursor is not - * available yet. - * @param from - * A list of column names representing the data to bind to the - * UI. Can be null if the cursor is not available yet. - * @param to - * The views that should display column in the "from" parameter. - * These should all be TextViews. The first N views in this list - * are given the values of the first N columns in the from - * parameter. Can be null if the cursor is not available yet. - * @param flags - * Flags used to determine the behavior of the adapter, as per - * {@link CursorAdapter#CursorAdapter(Context, Cursor, int)}. - */ - public SimpleDragSortCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to, int flags) { - super(context, layout, c, flags); - mTo = to; - mOriginalFrom = from; - findColumns(c, from); - } - - /** - * Binds all of the field names passed into the "to" parameter of the - * constructor with their corresponding cursor columns as specified in the - * "from" parameter. - * - * Binding occurs in two phases. First, if a - * {@link android.widget.SimpleCursorAdapter.ViewBinder} is available, - * {@link ViewBinder#setViewValue(android.view.View, android.database.Cursor, int)} - * is invoked. If the returned value is true, binding has occured. If the - * returned value is false and the view to bind is a TextView, - * {@link #setViewText(TextView, String)} is invoked. If the returned value - * is false and the view to bind is an ImageView, - * {@link #setViewImage(ImageView, String)} is invoked. If no appropriate - * binding can be found, an {@link IllegalStateException} is thrown. - * - * @throws IllegalStateException - * if binding cannot occur - * - * @see android.widget.CursorAdapter#bindView(android.view.View, - * android.content.Context, android.database.Cursor) - * @see #getViewBinder() - * @see #setViewBinder(android.widget.SimpleCursorAdapter.ViewBinder) - * @see #setViewImage(ImageView, String) - * @see #setViewText(TextView, String) - */ - @Override - public void bindView(View view, Context context, Cursor cursor) { - final ViewBinder binder = mViewBinder; - final int count = mTo.length; - final int[] from = mFrom; - final int[] to = mTo; - - for (int i = 0; i < count; i++) { - final View v = view.findViewById(to[i]); - if (v != null) { - boolean bound = false; - if (binder != null) { - bound = binder.setViewValue(v, cursor, from[i]); - } - - if (!bound) { - String text = cursor.getString(from[i]); - if (text == null) { - text = ""; - } - - if (v instanceof TextView) { - setViewText((TextView) v, text); - } else if (v instanceof ImageView) { - setViewImage((ImageView) v, text); - } else { - throw new IllegalStateException(v.getClass().getName() + " is not a " - + " view that can be bounds by this SimpleCursorAdapter"); - } - } - } - } - } - - /** - * Returns the {@link ViewBinder} used to bind data to views. - * - * @return a ViewBinder or null if the binder does not exist - * - * @see #bindView(android.view.View, android.content.Context, - * android.database.Cursor) - * @see #setViewBinder(android.widget.SimpleCursorAdapter.ViewBinder) - */ - public ViewBinder getViewBinder() { - return mViewBinder; - } - - /** - * Sets the binder used to bind data to views. - * - * @param viewBinder - * the binder used to bind data to views, can be null to remove - * the existing binder - * - * @see #bindView(android.view.View, android.content.Context, - * android.database.Cursor) - * @see #getViewBinder() - */ - public void setViewBinder(ViewBinder viewBinder) { - mViewBinder = viewBinder; - } - - /** - * Called by bindView() to set the image for an ImageView but only if there - * is no existing ViewBinder or if the existing ViewBinder cannot handle - * binding to an ImageView. - * - * By default, the value will be treated as an image resource. If the value - * cannot be used as an image resource, the value is used as an image Uri. - * - * Intended to be overridden by Adapters that need to setFilter strings - * retrieved from the database. - * - * @param v - * ImageView to receive an image - * @param value - * the value retrieved from the cursor - */ - public void setViewImage(ImageView v, String value) { - try { - v.setImageResource(Integer.parseInt(value)); - } catch (NumberFormatException nfe) { - v.setImageURI(Uri.parse(value)); - } - } - - /** - * Called by bindView() to set the text for a TextView but only if there is - * no existing ViewBinder or if the existing ViewBinder cannot handle - * binding to a TextView. - * - * Intended to be overridden by Adapters that need to setFilter strings - * retrieved from the database. - * - * @param v - * TextView to receive text - * @param text - * the text to be set for the TextView - */ - public void setViewText(TextView v, String text) { - v.setText(text); - } - - /** - * Return the index of the column used to get a String representation of the - * Cursor. - * - * @return a valid index in the current Cursor or -1 - * - * @see android.widget.CursorAdapter#convertToString(android.database.Cursor) - * @see #setStringConversionColumn(int) - * @see #setCursorToStringConverter(android.widget.SimpleCursorAdapter.CursorToStringConverter) - * @see #getCursorToStringConverter() - */ - public int getStringConversionColumn() { - return mStringConversionColumn; - } - - /** - * Defines the index of the column in the Cursor used to get a String - * representation of that Cursor. The column is used to convert the Cursor - * to a String only when the current CursorToStringConverter is null. - * - * @param stringConversionColumn - * a valid index in the current Cursor or -1 to use the default - * conversion mechanism - * - * @see android.widget.CursorAdapter#convertToString(android.database.Cursor) - * @see #getStringConversionColumn() - * @see #setCursorToStringConverter(android.widget.SimpleCursorAdapter.CursorToStringConverter) - * @see #getCursorToStringConverter() - */ - public void setStringConversionColumn(int stringConversionColumn) { - mStringConversionColumn = stringConversionColumn; - } - - /** - * Returns the converter used to convert the filtering Cursor into a String. - * - * @return null if the converter does not exist or an instance of - * {@link android.widget.SimpleCursorAdapter.CursorToStringConverter} - * - * @see #setCursorToStringConverter(android.widget.SimpleCursorAdapter.CursorToStringConverter) - * @see #getStringConversionColumn() - * @see #setStringConversionColumn(int) - * @see android.widget.CursorAdapter#convertToString(android.database.Cursor) - */ - public CursorToStringConverter getCursorToStringConverter() { - return mCursorToStringConverter; - } - - /** - * Sets the converter used to convert the filtering Cursor into a String. - * - * @param cursorToStringConverter - * the Cursor to String converter, or null to remove the - * converter - * - * @see #setCursorToStringConverter(android.widget.SimpleCursorAdapter.CursorToStringConverter) - * @see #getStringConversionColumn() - * @see #setStringConversionColumn(int) - * @see android.widget.CursorAdapter#convertToString(android.database.Cursor) - */ - public void setCursorToStringConverter(CursorToStringConverter cursorToStringConverter) { - mCursorToStringConverter = cursorToStringConverter; - } - - /** - * Returns a CharSequence representation of the specified Cursor as defined - * by the current CursorToStringConverter. If no CursorToStringConverter has - * been set, the String conversion column is used instead. If the conversion - * column is -1, the returned String is empty if the cursor is null or - * Cursor.toString(). - * - * @param cursor - * the Cursor to convert to a CharSequence - * - * @return a non-null CharSequence representing the cursor - */ - @Override - public CharSequence convertToString(Cursor cursor) { - if (mCursorToStringConverter != null) { - return mCursorToStringConverter.convertToString(cursor); - } else if (mStringConversionColumn > -1) { - return cursor.getString(mStringConversionColumn); - } - - return super.convertToString(cursor); - } - - /** - * Create a map from an array of strings to an array of column-id integers - * in cursor c. If c is null, the array will be discarded. - * - * @param c - * the cursor to find the columns from - * @param from - * the Strings naming the columns of interest - */ - private void findColumns(Cursor c, String[] from) { - if (c != null) { - int i; - int count = from.length; - if (mFrom == null || mFrom.length != count) { - mFrom = new int[count]; - } - for (i = 0; i < count; i++) { - mFrom[i] = c.getColumnIndexOrThrow(from[i]); - } - } else { - mFrom = null; - } - } - - @Override - public Cursor swapCursor(Cursor c) { - // super.swapCursor() will notify observers before we have - // a valid mapping, make sure we have a mapping before this - // happens - findColumns(c, mOriginalFrom); - return super.swapCursor(c); - } - - /** - * Change the cursor and change the column-to-view mappings at the same - * time. - * - * @param c - * The database cursor. Can be null if the cursor is not - * available yet. - * @param from - * A list of column names representing the data to bind to the - * UI. Can be null if the cursor is not available yet. - * @param to - * The views that should display column in the "from" parameter. - * These should all be TextViews. The first N views in this list - * are given the values of the first N columns in the from - * parameter. Can be null if the cursor is not available yet. - */ - public void changeCursorAndColumns(Cursor c, String[] from, int[] to) { - mOriginalFrom = from; - mTo = to; - // super.changeCursor() will notify observers before we have - // a valid mapping, make sure we have a mapping before this - // happens - findColumns(c, mOriginalFrom); - super.changeCursor(c); - } - - /** - * This class can be used by external clients of SimpleCursorAdapter to bind - * values fom the Cursor to views. - * - * You should use this class to bind values from the Cursor to views that - * are not directly supported by SimpleCursorAdapter or to change the way - * binding occurs for views supported by SimpleCursorAdapter. - * - * @see SimpleCursorAdapter#bindView(android.view.View, - * android.content.Context, android.database.Cursor) - * @see SimpleCursorAdapter#setViewImage(ImageView, String) - * @see SimpleCursorAdapter#setViewText(TextView, String) - */ - public static interface ViewBinder { - /** - * Binds the Cursor column defined by the specified index to the - * specified view. - * - * When binding is handled by this ViewBinder, this method must return - * true. If this method returns false, SimpleCursorAdapter will attempts - * to handle the binding on its own. - * - * @param view - * the view to bind the data to - * @param cursor - * the cursor to get the data from - * @param columnIndex - * the column at which the data can be found in the cursor - * - * @return true if the data was bound to the view, false otherwise - */ - boolean setViewValue(View view, Cursor cursor, int columnIndex); - } - - /** - * This class can be used by external clients of SimpleCursorAdapter to - * define how the Cursor should be converted to a String. - * - * @see android.widget.CursorAdapter#convertToString(android.database.Cursor) - */ - public static interface CursorToStringConverter { - /** - * Returns a CharSequence representing the specified Cursor. - * - * @param cursor - * the cursor for which a CharSequence representation is - * requested - * - * @return a non-null CharSequence representing the cursor - */ - CharSequence convertToString(Cursor cursor); - } - -} diff --git a/Clover/app/src/main/java/com/mobeta/android/dslv/SimpleFloatViewManager.java b/Clover/app/src/main/java/com/mobeta/android/dslv/SimpleFloatViewManager.java deleted file mode 100644 index 27dd8328..00000000 --- a/Clover/app/src/main/java/com/mobeta/android/dslv/SimpleFloatViewManager.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.mobeta.android.dslv; - -import android.graphics.Bitmap; -import android.graphics.Color; -import android.graphics.Point; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.ListView; - -/** - * Simple implementation of the FloatViewManager class. Uses list items as they - * appear in the ListView to create the floating View. - */ -public class SimpleFloatViewManager implements DragSortListView.FloatViewManager { - - private Bitmap mFloatBitmap; - - private ImageView mImageView; - - private int mFloatBGColor = Color.BLACK; - - private ListView mListView; - - public SimpleFloatViewManager(ListView lv) { - mListView = lv; - } - - public void setBackgroundColor(int color) { - mFloatBGColor = color; - } - - /** - * This simple implementation creates a Bitmap copy of the list item - * currently shown at ListView position. - */ - @Override - public View onCreateFloatView(int position) { - // Guaranteed that this will not be null? I think so. Nope, got - // a NullPointerException once... - View v = mListView.getChildAt(position + mListView.getHeaderViewsCount() - mListView.getFirstVisiblePosition()); - - if (v == null) { - return null; - } - - v.setPressed(false); - - // Create a copy of the drawing cache so that it does not get - // recycled by the framework when the list tries to clean up memory - //v.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH); - v.setDrawingCacheEnabled(true); - mFloatBitmap = Bitmap.createBitmap(v.getDrawingCache()); - v.setDrawingCacheEnabled(false); - - if (mImageView == null) { - mImageView = new ImageView(mListView.getContext()); - } - mImageView.setBackgroundColor(mFloatBGColor); - mImageView.setPadding(0, 0, 0, 0); - mImageView.setImageBitmap(mFloatBitmap); - mImageView.setLayoutParams(new ViewGroup.LayoutParams(v.getWidth(), v.getHeight())); - - return mImageView; - } - - /** - * This does nothing - */ - @Override - public void onDragFloatView(View floatView, Point position, Point touch) { - // do nothing - } - - /** - * Removes the Bitmap from the ImageView created in onCreateFloatView() and - * tells the system to recycle it. - */ - @Override - public void onDestroyFloatView(View floatView) { - ((ImageView) floatView).setImageDrawable(null); - - mFloatBitmap.recycle(); - mFloatBitmap = null; - } - -} diff --git a/Clover/app/src/main/java/org/floens/chan/Chan.java b/Clover/app/src/main/java/org/floens/chan/Chan.java new file mode 100644 index 00000000..1c0986bd --- /dev/null +++ b/Clover/app/src/main/java/org/floens/chan/Chan.java @@ -0,0 +1,220 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.floens.chan; + +import android.app.Application; +import android.content.Context; +import android.content.pm.PackageManager; +import android.os.StrictMode; +import android.view.ViewConfiguration; + +import com.android.volley.RequestQueue; +import com.android.volley.toolbox.ImageLoader; +import com.android.volley.toolbox.Volley; +import com.squareup.leakcanary.LeakCanary; +import com.squareup.leakcanary.RefWatcher; + +import org.floens.chan.chan.ChanUrls; +import org.floens.chan.core.cache.FileCache; +import org.floens.chan.core.manager.BoardManager; +import org.floens.chan.core.manager.WatchManager; +import org.floens.chan.core.net.BitmapLruImageCache; +import org.floens.chan.core.reply.ReplyManager; +import org.floens.chan.core.settings.ChanSettings; +import org.floens.chan.database.DatabaseManager; +import org.floens.chan.utils.AndroidUtils; +import org.floens.chan.utils.Logger; + +import java.io.File; +import java.lang.reflect.Field; +import java.util.Locale; + +import de.greenrobot.event.EventBus; + +public class Chan extends Application { + private static final String TAG = "ChanApplication"; + + private static final long FILE_CACHE_DISK_SIZE = 50 * 1024 * 1024; + private static final String FILE_CACHE_NAME = "filecache"; + private static final int VOLLEY_LRU_CACHE_SIZE = 8 * 1024 * 1024; + private static final int VOLLEY_CACHE_SIZE = 10 * 1024 * 1024; + + public static Context con; + + private static Chan instance; + private static RequestQueue volleyRequestQueue; + private static com.android.volley.toolbox.ImageLoader imageLoader; + private static BoardManager boardManager; + private static WatchManager watchManager; + private static ReplyManager replyManager; + private static DatabaseManager databaseManager; + private static FileCache fileCache; + private static RefWatcher refWatcher; + + private String userAgent; + private int activityForegroundCounter = 0; + + public Chan() { + instance = this; + con = this; + } + + public static Chan getInstance() { + return instance; + } + + public static RequestQueue getVolleyRequestQueue() { + return volleyRequestQueue; + } + + public static ImageLoader getVolleyImageLoader() { + return imageLoader; + } + + public static BoardManager getBoardManager() { + return boardManager; + } + + public static WatchManager getWatchManager() { + return watchManager; + } + + public static ReplyManager getReplyManager() { + return replyManager; + } + + public static DatabaseManager getDatabaseManager() { + return databaseManager; + } + + public static FileCache getFileCache() { + return fileCache; + } + + public static RefWatcher getRefWatcher() { + return refWatcher; + } + + @Override + public void onCreate() { + super.onCreate(); + + // Force the overflow button to show, even on devices that have a + // physical button. + try { + ViewConfiguration config = ViewConfiguration.get(this); + Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey"); + if (menuKeyField != null) { + menuKeyField.setAccessible(true); + menuKeyField.setBoolean(config, false); + } + } catch (Exception e) { + } + + if (ChanBuild.DEVELOPER_MODE) { + refWatcher = LeakCanary.install(this); + StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build()); + StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().build()); + } + + AndroidUtils.init(); + + ChanUrls.loadScheme(ChanSettings.networkHttps.get()); + + // User agent is / + String version = ""; + try { + version = getPackageManager().getPackageInfo(getPackageName(), 0).versionName; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + version = version.toLowerCase(Locale.ENGLISH).replace(" ", "_"); + userAgent = getString(R.string.app_name) + "/" + version; + + cleanupOutdated(); + + File cacheDir = getExternalCacheDir() != null ? getExternalCacheDir() : getCacheDir(); + + replyManager = new ReplyManager(this); + + volleyRequestQueue = Volley.newRequestQueue(this, getUserAgent(), null, new File(cacheDir, Volley.DEFAULT_CACHE_DIR), VOLLEY_CACHE_SIZE); + imageLoader = new ImageLoader(volleyRequestQueue, new BitmapLruImageCache(VOLLEY_LRU_CACHE_SIZE)); + + fileCache = new FileCache(new File(cacheDir, FILE_CACHE_NAME), FILE_CACHE_DISK_SIZE, getUserAgent()); + + databaseManager = new DatabaseManager(this); + boardManager = new BoardManager(); + watchManager = new WatchManager(this); + } + + public String getUserAgent() { + return userAgent; + } + + public void activityEnteredForeground() { + boolean lastForeground = getApplicationInForeground(); + + activityForegroundCounter++; + + if (getApplicationInForeground() != lastForeground) { + EventBus.getDefault().post(new ForegroundChangedMessage(getApplicationInForeground())); + } + } + + public void activityEnteredBackground() { + boolean lastForeground = getApplicationInForeground(); + + activityForegroundCounter--; + if (activityForegroundCounter < 0) { + Logger.wtf(TAG, "activityForegroundCounter below 0"); + } + + if (getApplicationInForeground() != lastForeground) { + EventBus.getDefault().post(new ForegroundChangedMessage(getApplicationInForeground())); + } + } + + public boolean getApplicationInForeground() { + return activityForegroundCounter > 0; + } + + private void cleanupOutdated() { + File ionCacheFolder = new File(getCacheDir() + "/ion"); + if (ionCacheFolder.exists() && ionCacheFolder.isDirectory()) { + Logger.i(TAG, "Clearing old ion folder"); + for (File file : ionCacheFolder.listFiles()) { + if (!file.delete()) { + Logger.i(TAG, "Could not delete old ion file " + file.getName()); + } + } + if (!ionCacheFolder.delete()) { + Logger.i(TAG, "Could not delete old ion folder"); + } else { + Logger.i(TAG, "Deleted old ion folder"); + } + } + } + + public static class ForegroundChangedMessage { + public boolean inForeground; + + public ForegroundChangedMessage(boolean inForeground) { + this.inForeground = inForeground; + } + } +} diff --git a/Clover/app/src/main/java/org/floens/chan/ChanApplication.java b/Clover/app/src/main/java/org/floens/chan/ChanApplication.java index 2f137ced..4001cd19 100644 --- a/Clover/app/src/main/java/org/floens/chan/ChanApplication.java +++ b/Clover/app/src/main/java/org/floens/chan/ChanApplication.java @@ -17,207 +17,5 @@ */ package org.floens.chan; -import android.app.Application; -import android.content.Context; -import android.content.pm.PackageManager; -import android.os.StrictMode; -import android.view.ViewConfiguration; - -import com.android.volley.RequestQueue; -import com.android.volley.toolbox.ImageLoader; -import com.android.volley.toolbox.Volley; -import com.squareup.leakcanary.LeakCanary; -import com.squareup.leakcanary.RefWatcher; - -import org.floens.chan.chan.ChanUrls; -import org.floens.chan.core.manager.BoardManager; -import org.floens.chan.core.reply.ReplyManager; -import org.floens.chan.core.manager.WatchManager; -import org.floens.chan.core.net.BitmapLruImageCache; -import org.floens.chan.core.settings.ChanSettings; -import org.floens.chan.database.DatabaseManager; -import org.floens.chan.utils.AndroidUtils; -import org.floens.chan.utils.FileCache; -import org.floens.chan.utils.IconCache; -import org.floens.chan.utils.Logger; - -import java.io.File; -import java.lang.reflect.Field; -import java.util.Locale; - -import de.greenrobot.event.EventBus; - -public class ChanApplication extends Application { - private static final String TAG = "ChanApplication"; - - private static final long FILE_CACHE_DISK_SIZE = 50 * 1024 * 1024; - private static final String FILE_CACHE_NAME = "filecache"; - private static final int VOLLEY_LRU_CACHE_SIZE = 8 * 1024 * 1024; - private static final int VOLLEY_CACHE_SIZE = 10 * 1024 * 1024; - - public static Context con; - - private static ChanApplication instance; - private static RequestQueue volleyRequestQueue; - private static com.android.volley.toolbox.ImageLoader imageLoader; - private static BoardManager boardManager; - private static WatchManager watchManager; - private static ReplyManager replyManager; - private static DatabaseManager databaseManager; - private static FileCache fileCache; - private static RefWatcher refWatcher; - - private String userAgent; - private int activityForegroundCounter = 0; - - public ChanApplication() { - instance = this; - con = this; - } - - public static ChanApplication getInstance() { - return instance; - } - - public static RequestQueue getVolleyRequestQueue() { - return volleyRequestQueue; - } - - public static ImageLoader getVolleyImageLoader() { - return imageLoader; - } - - public static BoardManager getBoardManager() { - return boardManager; - } - - public static WatchManager getWatchManager() { - return watchManager; - } - - public static ReplyManager getReplyManager() { - return replyManager; - } - - public static DatabaseManager getDatabaseManager() { - return databaseManager; - } - - public static FileCache getFileCache() { - return fileCache; - } - - public static RefWatcher getRefWatcher() { - return refWatcher; - } - - @Override - public void onCreate() { - super.onCreate(); - - // Force the overflow button to show, even on devices that have a - // physical button. - try { - ViewConfiguration config = ViewConfiguration.get(this); - Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey"); - if (menuKeyField != null) { - menuKeyField.setAccessible(true); - menuKeyField.setBoolean(config, false); - } - } catch (Exception e) { - } - - if (ChanBuild.DEVELOPER_MODE) { - refWatcher = LeakCanary.install(this); - StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build()); - StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().build()); - } - - AndroidUtils.init(); - - ChanUrls.loadScheme(ChanSettings.getNetworkHttps()); - - // User agent is / - String version = ""; - try { - version = getPackageManager().getPackageInfo(getPackageName(), 0).versionName; - } catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); - } - version = version.toLowerCase(Locale.ENGLISH).replace(" ", "_"); - userAgent = getString(R.string.app_name) + "/" + version; - - IconCache.createIcons(this); - - cleanupOutdated(); - - File cacheDir = getExternalCacheDir() != null ? getExternalCacheDir() : getCacheDir(); - - replyManager = new ReplyManager(this); - - volleyRequestQueue = Volley.newRequestQueue(this, getUserAgent(), null, new File(cacheDir, Volley.DEFAULT_CACHE_DIR), VOLLEY_CACHE_SIZE); - imageLoader = new ImageLoader(volleyRequestQueue, new BitmapLruImageCache(VOLLEY_LRU_CACHE_SIZE)); - - fileCache = new FileCache(new File(cacheDir, FILE_CACHE_NAME), FILE_CACHE_DISK_SIZE, getUserAgent()); - - databaseManager = new DatabaseManager(this); - boardManager = new BoardManager(); - watchManager = new WatchManager(this); - } - - public String getUserAgent() { - return userAgent; - } - - public void activityEnteredForeground() { - boolean lastForeground = getApplicationInForeground(); - - activityForegroundCounter++; - - if (getApplicationInForeground() != lastForeground) { - EventBus.getDefault().post(new ForegroundChangedMessage(getApplicationInForeground())); - } - } - - public void activityEnteredBackground() { - boolean lastForeground = getApplicationInForeground(); - - activityForegroundCounter--; - if (activityForegroundCounter < 0) { - Logger.wtf(TAG, "activityForegroundCounter below 0"); - } - - if (getApplicationInForeground() != lastForeground) { - EventBus.getDefault().post(new ForegroundChangedMessage(getApplicationInForeground())); - } - } - - public boolean getApplicationInForeground() { - return activityForegroundCounter > 0; - } - - private void cleanupOutdated() { - File ionCacheFolder = new File(getCacheDir() + "/ion"); - if (ionCacheFolder.exists() && ionCacheFolder.isDirectory()) { - Logger.i(TAG, "Clearing old ion folder"); - for (File file : ionCacheFolder.listFiles()) { - if (!file.delete()) { - Logger.i(TAG, "Could not delete old ion file " + file.getName()); - } - } - if (!ionCacheFolder.delete()) { - Logger.i(TAG, "Could not delete old ion folder"); - } else { - Logger.i(TAG, "Deleted old ion folder"); - } - } - } - - public static class ForegroundChangedMessage { - public boolean inForeground; - - public ForegroundChangedMessage(boolean inForeground) { - this.inForeground = inForeground; - } - } +public class ChanApplication extends Chan { } diff --git a/Clover/app/src/main/java/org/floens/chan/chan/ImageSearch.java b/Clover/app/src/main/java/org/floens/chan/chan/ImageSearch.java index 4c1df343..76029eb9 100644 --- a/Clover/app/src/main/java/org/floens/chan/chan/ImageSearch.java +++ b/Clover/app/src/main/java/org/floens/chan/chan/ImageSearch.java @@ -17,8 +17,6 @@ */ package org.floens.chan.chan; -import org.floens.chan.R; - import java.util.ArrayList; import java.util.List; @@ -34,7 +32,7 @@ public abstract class ImageSearch { static { engines.add(new ImageSearch() { public int getId() { - return R.id.action_0; + return 0; } public String getName() { @@ -48,7 +46,7 @@ public abstract class ImageSearch { engines.add(new ImageSearch() { public int getId() { - return R.id.action_1; + return 1; } public String getName() { diff --git a/Clover/app/src/main/java/org/floens/chan/controller/ControllerLogic.java b/Clover/app/src/main/java/org/floens/chan/controller/ControllerLogic.java index a1d37c8c..bc25f1ee 100644 --- a/Clover/app/src/main/java/org/floens/chan/controller/ControllerLogic.java +++ b/Clover/app/src/main/java/org/floens/chan/controller/ControllerLogic.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.controller; import android.view.ViewGroup; diff --git a/Clover/app/src/main/java/org/floens/chan/controller/FadeInTransition.java b/Clover/app/src/main/java/org/floens/chan/controller/FadeInTransition.java index 2475e711..ec3c3329 100644 --- a/Clover/app/src/main/java/org/floens/chan/controller/FadeInTransition.java +++ b/Clover/app/src/main/java/org/floens/chan/controller/FadeInTransition.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.controller; import android.animation.Animator; diff --git a/Clover/app/src/main/java/org/floens/chan/controller/FadeOutTransition.java b/Clover/app/src/main/java/org/floens/chan/controller/FadeOutTransition.java index c0ab0bed..30868e47 100644 --- a/Clover/app/src/main/java/org/floens/chan/controller/FadeOutTransition.java +++ b/Clover/app/src/main/java/org/floens/chan/controller/FadeOutTransition.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.controller; import android.animation.Animator; diff --git a/Clover/app/src/main/java/org/floens/chan/utils/FileCache.java b/Clover/app/src/main/java/org/floens/chan/core/cache/FileCache.java similarity index 98% rename from Clover/app/src/main/java/org/floens/chan/utils/FileCache.java rename to Clover/app/src/main/java/org/floens/chan/core/cache/FileCache.java index 0fc17225..2b0af178 100644 --- a/Clover/app/src/main/java/org/floens/chan/utils/FileCache.java +++ b/Clover/app/src/main/java/org/floens/chan/core/cache/FileCache.java @@ -15,10 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package org.floens.chan.utils; - -import android.os.Handler; -import android.os.Looper; +package org.floens.chan.core.cache; import com.squareup.okhttp.Call; import com.squareup.okhttp.OkHttpClient; @@ -28,6 +25,10 @@ import com.squareup.okhttp.Response; import com.squareup.okhttp.ResponseBody; import com.squareup.okhttp.internal.Util; +import org.floens.chan.utils.AndroidUtils; +import org.floens.chan.utils.Logger; +import org.floens.chan.utils.Time; + import java.io.BufferedOutputStream; import java.io.Closeable; import java.io.File; diff --git a/Clover/app/src/main/java/org/floens/chan/core/loader/ChanLoader.java b/Clover/app/src/main/java/org/floens/chan/core/loader/ChanLoader.java index 72f9d4af..8b8b0912 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/loader/ChanLoader.java +++ b/Clover/app/src/main/java/org/floens/chan/core/loader/ChanLoader.java @@ -18,13 +18,11 @@ package org.floens.chan.core.loader; import android.text.TextUtils; -import android.util.SparseArray; import com.android.volley.Response; -import com.android.volley.ServerError; import com.android.volley.VolleyError; -import org.floens.chan.ChanApplication; +import org.floens.chan.Chan; import org.floens.chan.core.model.ChanThread; import org.floens.chan.core.model.Loadable; import org.floens.chan.core.model.Post; @@ -48,7 +46,6 @@ public class ChanLoader { private final List listeners = new ArrayList<>(); private final Loadable loadable; - private final SparseArray postsById = new SparseArray<>(); private ChanThread thread; private boolean destroyed = false; @@ -62,6 +59,10 @@ public class ChanLoader { public ChanLoader(Loadable loadable) { this.loadable = loadable; + + if (loadable.mode == Loadable.Mode.BOARD) { + loadable.mode = Loadable.Mode.CATALOG; + } } /** @@ -129,7 +130,7 @@ public class ChanLoader { request.cancel(); } - if (loadable.isBoardMode() || loadable.isCatalogMode()) { + if (loadable.isCatalogMode()) { loadable.no = 0; loadable.listViewIndex = 0; loadable.listViewTop = 0; @@ -147,16 +148,7 @@ public class ChanLoader { public void requestMoreData() { clearTimer(); - if (loadable.isBoardMode()) { - if (request != null) { - // finish the last board load first - return; - } - - loadable.no++; - - request = getData(); - } else if (loadable.isThreadMode()) { + if (loadable.isThreadMode()) { if (request != null) { return; } @@ -180,18 +172,12 @@ public class ChanLoader { return request != null; } - public Post findPostById(int id) { - return postsById.get(id); - } - public Loadable getLoadable() { return loadable; } /** * Get the time in milliseconds until another loadMore is recommended - * - * @return */ public long getTimeUntilLoadMore() { if (request != null) { @@ -272,7 +258,7 @@ public class ChanLoader { } ); - ChanApplication.getVolleyRequestQueue().add(request); + Chan.getVolleyRequestQueue().add(request); return request; } @@ -285,31 +271,8 @@ public class ChanLoader { thread = new ChanThread(loadable, new ArrayList()); } - if (loadable.isThreadMode() || loadable.isCatalogMode()) { - thread.posts.clear(); - thread.posts.addAll(result); - postsById.clear(); - for (Post post : result) { - postsById.append(post.no, post); - } - } else if (loadable.isBoardMode()) { - // Only add new posts - boolean flag; - for (Post post : result) { - flag = true; - for (Post cached : thread.posts) { - if (post.no == cached.no) { - flag = false; - break; - } - } - - if (flag) { - thread.posts.add(post); - postsById.append(post.no, post); - } - } - } + thread.posts.clear(); + thread.posts.addAll(result); if (loadable.isThreadMode() && thread.posts.size() > 0) { thread.op = thread.posts.get(0); @@ -346,11 +309,6 @@ public class ChanLoader { Logger.e(TAG, "Loading error"); - // 404 with more pages already loaded means endofline - if ((error instanceof ServerError) && loadable.isBoardMode() && loadable.no > 0) { - error = new EndOfLineException(); - } - clearTimer(); for (ChanLoaderCallback l : listeners) { diff --git a/Clover/app/src/main/java/org/floens/chan/core/loader/ChanParser.java b/Clover/app/src/main/java/org/floens/chan/core/loader/ChanParser.java index 27892616..d62627d0 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/loader/ChanParser.java +++ b/Clover/app/src/main/java/org/floens/chan/core/loader/ChanParser.java @@ -30,11 +30,11 @@ import android.text.style.StrikethroughSpan; import android.text.style.StyleSpan; import android.text.style.TypefaceSpan; -import org.floens.chan.ChanApplication; +import org.floens.chan.Chan; import org.floens.chan.R; -import org.floens.chan.core.settings.ChanSettings; import org.floens.chan.core.model.Post; import org.floens.chan.core.model.PostLinkable; +import org.floens.chan.core.settings.ChanSettings; import org.floens.chan.utils.AndroidUtils; import org.floens.chan.utils.ThemeHelper; import org.jsoup.Jsoup; @@ -90,11 +90,11 @@ public class ChanParser { } private void parseSpans(Post post) { - boolean anonymize = ChanSettings.getAnonymize(); - boolean anonymizeIds = ChanSettings.getAnonymizeIds(); + boolean anonymize = ChanSettings.anonymize.get(); + boolean anonymizeIds = ChanSettings.anonymizeIds.get(); if (anonymize) { - post.name = ChanApplication.getInstance().getString(R.string.default_name); + post.name = "Anonymous"; post.tripcode = ""; } @@ -376,7 +376,7 @@ public class ChanParser { // Append You when it's a reply to an saved reply // todo synchronized - if (ChanApplication.getDatabaseManager().isSavedReply(post.board, id)) { + if (Chan.getDatabaseManager().isSavedReply(post.board, id)) { key += " (You)"; } } diff --git a/Clover/app/src/main/java/org/floens/chan/core/loader/EndOfLineException.java b/Clover/app/src/main/java/org/floens/chan/core/loader/EndOfLineException.java deleted file mode 100644 index ae98a8be..00000000 --- a/Clover/app/src/main/java/org/floens/chan/core/loader/EndOfLineException.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Clover - 4chan browser https://github.com/Floens/Clover/ - * Copyright (C) 2014 Floens - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.floens.chan.core.loader; - -import com.android.volley.NetworkResponse; -import com.android.volley.VolleyError; - -@SuppressWarnings("serial") -public class EndOfLineException extends VolleyError { - public EndOfLineException(NetworkResponse networkResponse) { - super(networkResponse); - } - - public EndOfLineException() { - super(); - } - - @Override - public String getMessage() { - return "End of the line"; - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/core/manager/BoardManager.java b/Clover/app/src/main/java/org/floens/chan/core/manager/BoardManager.java index d2bf5c6f..bcd36854 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/manager/BoardManager.java +++ b/Clover/app/src/main/java/org/floens/chan/core/manager/BoardManager.java @@ -20,7 +20,7 @@ package org.floens.chan.core.manager; import com.android.volley.Response; import com.android.volley.VolleyError; -import org.floens.chan.ChanApplication; +import org.floens.chan.Chan; import org.floens.chan.chan.ChanUrls; import org.floens.chan.core.model.Board; import org.floens.chan.core.net.BoardsRequest; @@ -84,7 +84,7 @@ public class BoardManager { } public void updateSavedBoards() { - ChanApplication.getDatabaseManager().updateBoards(allBoards); + Chan.getDatabaseManager().updateBoards(allBoards); notifyChanged(); } @@ -103,12 +103,12 @@ public class BoardManager { private void storeBoards() { updateByValueMap(); - ChanApplication.getDatabaseManager().setBoards(allBoards); + Chan.getDatabaseManager().setBoards(allBoards); notifyChanged(); } private void loadBoards() { - allBoards = ChanApplication.getDatabaseManager().getBoards(); + allBoards = Chan.getDatabaseManager().getBoards(); if (allBoards.size() == 0) { Logger.d(TAG, "Loading default boards"); allBoards = getDefaultBoards(); @@ -149,7 +149,7 @@ public class BoardManager { } private void loadFromServer() { - ChanApplication.getVolleyRequestQueue().add( + Chan.getVolleyRequestQueue().add( new BoardsRequest(ChanUrls.getBoardsUrl(), new Response.Listener>() { @Override public void onResponse(List data) { diff --git a/Clover/app/src/main/java/org/floens/chan/core/manager/ThreadManager.java b/Clover/app/src/main/java/org/floens/chan/core/manager/ThreadManager.java deleted file mode 100644 index 5de96cfc..00000000 --- a/Clover/app/src/main/java/org/floens/chan/core/manager/ThreadManager.java +++ /dev/null @@ -1,604 +0,0 @@ -/* - * Clover - 4chan browser https://github.com/Floens/Clover/ - * Copyright (C) 2014 Floens - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.floens.chan.core.manager; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.FragmentTransaction; -import android.app.ProgressDialog; -import android.content.ClipData; -import android.content.ClipboardManager; -import android.content.Context; -import android.content.DialogInterface; -import android.content.DialogInterface.OnClickListener; -import android.content.Intent; -import android.text.TextUtils; -import android.view.Menu; -import android.view.MenuItem; -import android.widget.CheckBox; -import android.widget.LinearLayout; -import android.widget.PopupMenu; -import android.widget.Toast; - -import com.android.volley.VolleyError; - -import org.floens.chan.ChanApplication; -import org.floens.chan.R; -import org.floens.chan.chan.ChanUrls; -import org.floens.chan.core.settings.ChanSettings; -import org.floens.chan.core.loader.ChanLoader; -import org.floens.chan.core.loader.LoaderPool; -import org.floens.chan.core.reply.ReplyManager.DeleteListener; -import org.floens.chan.core.reply.ReplyManager.DeleteResponse; -import org.floens.chan.core.model.ChanThread; -import org.floens.chan.core.model.Loadable; -import org.floens.chan.core.model.Pin; -import org.floens.chan.core.model.Post; -import org.floens.chan.core.model.PostLinkable; -import org.floens.chan.core.model.SavedReply; -import org.floens.chan.ui.activity.ReplyActivity; -import org.floens.chan.ui.fragment.PostRepliesFragment; -import org.floens.chan.ui.fragment.ReplyFragment; -import org.floens.chan.utils.AndroidUtils; -import org.floens.chan.utils.Logger; - -import java.util.ArrayList; -import java.util.List; - -import static org.floens.chan.utils.AndroidUtils.dp; - -/** - * All PostView's need to have this referenced. This manages some things like - * pages, starting and stopping of loading, handling linkables, replies popups - * etc. onDestroy, onStart and onStop must be called from the activity/fragment - */ -public class ThreadManager implements ChanLoader.ChanLoaderCallback { - public static enum ViewMode { - LIST, GRID - } - - private static final String TAG = "ThreadManager"; - - private final Activity activity; - private final ThreadManagerListener threadManagerListener; - private final List popupQueue = new ArrayList<>(); - private PostRepliesFragment currentPopupFragment; - private int highlightedPost = -1; - private int lastPost = -1; - private String highlightedId = null; - - private ChanLoader chanLoader; - - public ThreadManager(Activity activity, final ThreadManagerListener listener) { - this.activity = activity; - threadManagerListener = listener; - } - - public void onDestroy() { - unbindLoader(); - } - - public void onStart() { - if (chanLoader != null) { - if (isWatching()) { - chanLoader.setAutoLoadMore(true); - chanLoader.requestMoreDataAndResetTimer(); - } - } - } - - public void onStop() { - if (chanLoader != null) { - chanLoader.setAutoLoadMore(false); - } - } - - public void bindLoader(Loadable loadable) { - if (chanLoader != null) { - unbindLoader(); - } - - chanLoader = LoaderPool.getInstance().obtain(loadable, this); - if (isWatching()) { - chanLoader.setAutoLoadMore(true); - } - } - - public void unbindLoader() { - if (chanLoader != null) { - chanLoader.setAutoLoadMore(false); - LoaderPool.getInstance().release(chanLoader, this); - chanLoader = null; - } else { - Logger.e(TAG, "Loader already unbinded"); - } - - highlightedPost = -1; - lastPost = -1; - highlightedId = null; - } - - public void bottomPostViewed() { - if (chanLoader.getLoadable().isThreadMode() && chanLoader.getThread() != null && chanLoader.getThread().posts.size() > 0) { - chanLoader.getLoadable().lastViewed = chanLoader.getThread().posts.get(chanLoader.getThread().posts.size() - 1).no; - } - - Pin pin = ChanApplication.getWatchManager().findPinByLoadable(chanLoader.getLoadable()); - if (pin != null) { - pin.onBottomPostViewed(); - ChanApplication.getWatchManager().onPinsChanged(); - } - } - - public boolean isWatching() { - if (!chanLoader.getLoadable().isThreadMode()) { - return false; - } else if (!ChanSettings.getThreadAutoRefresh()) { - return false; - } else if (chanLoader.getThread() != null && chanLoader.getThread().closed) { - return false; - } else { - return true; - } - } - - public void requestData() { - if (chanLoader != null) { - chanLoader.requestData(); - } else { - Logger.e(TAG, "Loader null in requestData"); - } - } - - /** - * Called by postadapter and threadwatchcounterview.onclick - */ - public void requestNextData() { - if (chanLoader != null) { - chanLoader.requestMoreData(); - } else { - Logger.e(TAG, "Loader null in requestData"); - } - } - - @Override - public void onChanLoaderError(VolleyError error) { - threadManagerListener.onThreadLoadError(error); - } - - @Override - public void onChanLoaderData(ChanThread thread) { - if (!isWatching()) { - chanLoader.setAutoLoadMore(false); - } - - if (thread.posts.size() > 0) { - lastPost = thread.posts.get(thread.posts.size() - 1).no; - } - - threadManagerListener.onThreadLoaded(thread); - } - - public boolean hasLoader() { - return chanLoader != null; - } - - public Post findPostById(int id) { - if (chanLoader == null) - return null; - return chanLoader.findPostById(id); - } - - public Loadable getLoadable() { - if (chanLoader == null) - return null; - return chanLoader.getLoadable(); - } - - public ChanLoader getChanLoader() { - return chanLoader; - } - - public void onThumbnailClicked(Post post) { - threadManagerListener.onThumbnailClicked(post); - } - - public void onPostClicked(Post post) { - if (chanLoader != null) { - threadManagerListener.onPostClicked(post); - } - } - - public void showPostOptions(final Post post, PopupMenu popupMenu) { - Menu menu = popupMenu.getMenu(); - - if (chanLoader.getLoadable().isBoardMode() || chanLoader.getLoadable().isCatalogMode()) { - menu.add(Menu.NONE, 9, Menu.NONE, activity.getString(R.string.action_pin)); - } - -// if (chanLoader.getLoadable().isThreadMode()) { -// menu.add(Menu.NONE, 10, Menu.NONE, activity.getString(R.string.post_quick_reply)); -// } - - String[] baseOptions = activity.getResources().getStringArray(R.array.post_options); - for (int i = 0; i < baseOptions.length; i++) { - menu.add(Menu.NONE, i, Menu.NONE, baseOptions[i]); - } - - if (!TextUtils.isEmpty(post.id)) { - menu.add(Menu.NONE, 6, Menu.NONE, activity.getString(R.string.post_highlight_id)); - } - - // Only add the delete option when the post is a saved reply - if (ChanApplication.getDatabaseManager().isSavedReply(post.board, post.no)) { - menu.add(Menu.NONE, 7, Menu.NONE, activity.getString(R.string.delete)); - } - - if (ChanSettings.getDeveloper()) { - menu.add(Menu.NONE, 8, Menu.NONE, "Make this a saved reply"); - } - - popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { - @Override - public boolean onMenuItemClick(final MenuItem item) { - switch (item.getItemId()) { - case 10: // Quick reply - openReply(false); - // Pass through - case 0: // Quote -// ChanApplication.getReplyManager().quote(post.no); - break; - case 1: // Quote inline -// ChanApplication.getReplyManager().quoteInline(post.no, post.comment.toString()); - break; - case 2: // Info - showPostInfo(post); - break; - case 3: // Show clickables - showPostLinkables(post); - break; - case 4: // Copy text - copyToClipboard(post.comment.toString()); - break; - case 5: // Report - AndroidUtils.openWebView(activity, "Report /" + post.board + "/" + post.no, ChanUrls.getReportUrl(post.board, post.no)); - break; - case 6: // Id - highlightedId = post.id; - threadManagerListener.onRefreshView(); - break; - case 7: // Delete - deletePost(post); - break; - case 8: // Save reply - ChanApplication.getDatabaseManager().saveReply(new SavedReply(post.board, post.no, "foo")); - break; - case 9: // Pin - ChanApplication.getWatchManager().addPin(post); - break; - } - return false; - } - }); - } - - public void openReply(boolean startInActivity) { - if (chanLoader == null) - return; - - if (startInActivity) { - ReplyActivity.setLoadable(chanLoader.getLoadable()); - Intent i = new Intent(activity, ReplyActivity.class); - activity.startActivity(i); - } else { - ReplyFragment reply = ReplyFragment.newInstance(chanLoader.getLoadable(), true); - reply.show(activity.getFragmentManager(), "replyDialog"); - } - } - - public void onPostLinkableClicked(PostLinkable linkable) { - handleLinkableSelected(linkable); - } - - public void scrollToPost(int post) { - threadManagerListener.onScrollTo(post); - } - - public void highlightPost(int post) { - highlightedPost = post; - } - - public boolean isPostHightlighted(Post post) { - return (highlightedPost >= 0 && post.no == highlightedPost) || (highlightedId != null && post.id.equals(highlightedId)); - } - - public boolean isPostLastSeen(Post post) { - return post.no == chanLoader.getLoadable().lastViewed && post.no != lastPost; - } - - private void copyToClipboard(String comment) { - ClipboardManager clipboard = (ClipboardManager) activity.getSystemService(Context.CLIPBOARD_SERVICE); - ClipData clip = ClipData.newPlainText("Post text", comment); - clipboard.setPrimaryClip(clip); - Toast.makeText(activity, R.string.post_text_copied_to_clipboard, Toast.LENGTH_SHORT).show(); - } - - private void showPostInfo(Post post) { - String text = ""; - - if (post.hasImage) { - text += "File: " + post.filename + "." + post.ext + " \nDimensions: " + post.imageWidth + "x" - + post.imageHeight + "\nSize: " + AndroidUtils.getReadableFileSize(post.fileSize, false) + "\n\n"; - } - - text += "Time: " + post.date; - - if (!TextUtils.isEmpty(post.id)) { - text += "\nId: " + post.id; - } - - if (!TextUtils.isEmpty(post.tripcode)) { - text += "\nTripcode: " + post.tripcode; - } - - if (!TextUtils.isEmpty(post.countryName)) { - text += "\nCountry: " + post.countryName; - } - - if (!TextUtils.isEmpty(post.capcode)) { - text += "\nCapcode: " + post.capcode; - } - - AlertDialog dialog = new AlertDialog.Builder(activity).setTitle(R.string.post_info).setMessage(text) - .setNeutralButton(android.R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - } - }).create(); - - dialog.show(); - } - - /** - * Show a list of things that can be clicked in a list to the user. - * - * @param post The post that was clicked. - */ - public void showPostLinkables(Post post) { - AlertDialog.Builder builder = new AlertDialog.Builder(activity); - final ArrayList linkables = post.linkables; - - if (linkables.size() > 0) { - String[] keys = new String[linkables.size()]; - for (int i = 0; i < linkables.size(); i++) { - keys[i] = linkables.get(i).key; - } - - builder.setItems(keys, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - handleLinkableSelected(linkables.get(which)); - } - }); - - AlertDialog dialog = builder.create(); - dialog.show(); - } - } - - public void showPostReplies(Post post) { - RepliesPopup l = new RepliesPopup(); - List p = new ArrayList<>(); - for (int no : post.repliesFrom) { - Post r = findPostById(no); - if (r != null) { - p.add(r); - } - } - l.posts = p; - l.forNo = post.no; - if (p.size() > 0) { - showPostsRepliesFragment(l); - } - } - - public ThreadManager.ViewMode getViewMode() { - return threadManagerListener.getViewMode(); - } - - /** - * Handle when a linkable has been clicked. - * - * @param linkable the selected linkable. - */ - private void handleLinkableSelected(final PostLinkable linkable) { - if (linkable.type == PostLinkable.Type.QUOTE) { - Post post = findPostById((Integer) linkable.value); - if (post != null) { - RepliesPopup l = new RepliesPopup(); - l.forNo = (Integer) linkable.value; - l.posts.add(post); - showPostsRepliesFragment(l); - } - } else if (linkable.type == PostLinkable.Type.LINK) { - if (ChanSettings.getOpenLinkConfirmation()) { - new AlertDialog.Builder(activity) - .setNegativeButton(R.string.cancel, null) - .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - AndroidUtils.openLink((String) linkable.value); - } - }) - .setTitle(R.string.open_link_confirmation) - .setMessage((String) linkable.value) - .show(); - } else { - AndroidUtils.openLink((String) linkable.value); - } - } else if (linkable.type == PostLinkable.Type.THREAD) { - final PostLinkable.ThreadLink link = (PostLinkable.ThreadLink) linkable.value; - final Loadable thread = new Loadable(link.board, link.threadId); - - new AlertDialog.Builder(activity) - .setNegativeButton(R.string.cancel, null) - .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(final DialogInterface dialog, final int which) { - threadManagerListener.onOpenThread(thread, link.postId); - } - }) - .setTitle(R.string.open_thread_confirmation) - .setMessage("/" + thread.board + "/" + thread.no) - .show(); - } - } - - private void showPostsRepliesFragment(RepliesPopup repliesPopup) { - // Post popups are now queued up, more than 32 popups on top of each - // other makes the system crash! - popupQueue.add(repliesPopup); - - if (currentPopupFragment != null) { - currentPopupFragment.dismissNoCallback(); - } - -// PostRepliesFragment popup = PostRepliesFragment.newInstance(repliesPopup, this); - PostRepliesFragment popup = null; - FragmentTransaction ft = activity.getFragmentManager().beginTransaction(); - ft.add(popup, "postPopup"); - ft.commitAllowingStateLoss(); - - currentPopupFragment = popup; - } - - public void onPostRepliesPop() { - if (popupQueue.size() == 0) - return; - - popupQueue.remove(popupQueue.size() - 1); - - if (popupQueue.size() > 0) { -// PostRepliesFragment popup = PostRepliesFragment.newInstance(popupQueue.get(popupQueue.size() - 1), this); - PostRepliesFragment popup = null; - FragmentTransaction ft = activity.getFragmentManager().beginTransaction(); - ft.add(popup, "postPopup"); - ft.commit(); - - currentPopupFragment = popup; - } else { - currentPopupFragment = null; - } - } - - public void closeAllPostFragments() { - popupQueue.clear(); - currentPopupFragment = null; - } - - public boolean arePostRepliesOpen() { - return popupQueue.size() > 0; - } - - private void deletePost(final Post post) { - final CheckBox checkBox = new CheckBox(activity); - checkBox.setText(R.string.delete_image_only); - - LinearLayout wrapper = new LinearLayout(activity); - wrapper.addView(checkBox); - int padding = dp(8f); - wrapper.setPadding(padding, padding, padding, padding); - - new AlertDialog.Builder(activity).setTitle(R.string.delete_confirm).setView(wrapper) - .setPositiveButton(R.string.delete, new OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - doDeletePost(post, checkBox.isChecked()); - } - }).setNegativeButton(R.string.cancel, new OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - } - }).show(); - } - - private void doDeletePost(Post post, boolean onlyImageDelete) { - SavedReply reply = ChanApplication.getDatabaseManager().getSavedReply(post.board, post.no); - if (reply == null) { - /* - * reply = new SavedReply(); reply.board = "g"; reply.no = 1234; - * reply.password = "boom"; - */ - return; - } - - final ProgressDialog dialog = ProgressDialog.show(activity, null, activity.getString(R.string.delete_wait)); - - ChanApplication.getReplyManager().postDelete(reply, onlyImageDelete, new DeleteListener() { - @Override - public void onResponse(DeleteResponse response) { - dialog.dismiss(); - - if (response.isNetworkError || response.isUserError) { - int resId; - - if (response.isTooSoonError) { - resId = R.string.delete_too_soon; - } else if (response.isInvalidPassword) { - resId = R.string.delete_password_incorrect; - } else if (response.isTooOldError) { - resId = R.string.delete_too_old; - } else { - resId = R.string.delete_fail; - } - - Toast.makeText(activity, resId, Toast.LENGTH_LONG).show(); - } else if (response.isSuccessful) { - Toast.makeText(activity, R.string.delete_success, Toast.LENGTH_SHORT).show(); - } else { - Toast.makeText(activity, R.string.delete_fail, Toast.LENGTH_LONG).show(); - } - } - }); - } - - public interface ThreadManagerListener { - void onThreadLoaded(ChanThread thread); - - void onThreadLoadError(VolleyError error); - - void onPostClicked(Post post); - - void onThumbnailClicked(Post post); - - void onScrollTo(int post); - - void onRefreshView(); - - void onOpenThread(Loadable thread, int highlightedPost); - - ThreadManager.ViewMode getViewMode(); - } - - public static class RepliesPopup { - public List posts = new ArrayList<>(); - public int listViewIndex; - public int listViewTop; - public int forNo = -1; - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/core/manager/WatchManager.java b/Clover/app/src/main/java/org/floens/chan/core/manager/WatchManager.java index ff2ba790..f019ed6d 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/manager/WatchManager.java +++ b/Clover/app/src/main/java/org/floens/chan/core/manager/WatchManager.java @@ -20,7 +20,7 @@ package org.floens.chan.core.manager; import android.content.Context; import android.content.Intent; -import org.floens.chan.ChanApplication; +import org.floens.chan.Chan; import org.floens.chan.core.model.Loadable; import org.floens.chan.core.model.Pin; import org.floens.chan.core.model.Post; @@ -51,7 +51,7 @@ public class WatchManager { public WatchManager(Context context) { this.context = context; - pins = ChanApplication.getDatabaseManager().getPinned(); + pins = Chan.getDatabaseManager().getPinned(); EventBus.getDefault().register(this); @@ -122,7 +122,7 @@ public class WatchManager { } pins.add(pin); - ChanApplication.getDatabaseManager().addPin(pin); + Chan.getDatabaseManager().addPin(pin); onPinsChanged(); @@ -161,7 +161,7 @@ public class WatchManager { public void removePin(Pin pin) { pins.remove(pin); pin.destroyWatcher(); - ChanApplication.getDatabaseManager().removePin(pin); + Chan.getDatabaseManager().removePin(pin); onPinsChanged(); @@ -174,7 +174,7 @@ public class WatchManager { * @param pin */ public void updatePin(Pin pin) { - ChanApplication.getDatabaseManager().updatePin(pin); + Chan.getDatabaseManager().updatePin(pin); onPinsChanged(); @@ -185,15 +185,15 @@ public class WatchManager { * Updates all the pins to the database. */ public void updateDatabase() { - ChanApplication.getDatabaseManager().updatePins(pins); + Chan.getDatabaseManager().updatePins(pins); } public void toggleWatch(Pin pin) { pin.watching = !pin.watching; EventBus.getDefault().post(new PinChangedMessage(pin)); - ChanApplication.getWatchManager().onPinsChanged(); - ChanApplication.getWatchManager().invokeLoadNow(); + Chan.getWatchManager().onPinsChanged(); + Chan.getWatchManager().invokeLoadNow(); } public void pinWatcherUpdated(Pin pin) { @@ -231,7 +231,7 @@ public class WatchManager { } } - public void onEvent(ChanApplication.ForegroundChangedMessage message) { + public void onEvent(Chan.ForegroundChangedMessage message) { updateNotificationServiceState(); updateTimerState(true); } @@ -259,11 +259,11 @@ public class WatchManager { } public boolean getWatchBackgroundEnabled() { - return ChanSettings.getWatchBackgroundEnabled(); + return ChanSettings.watchBackground.get(); } private void updatePinWatchers() { - updatePinWatchers(ChanSettings.getWatchEnabled()); + updatePinWatchers(ChanSettings.watchEnabled.get()); } private void updatePinWatchers(boolean watchEnabled) { @@ -294,9 +294,9 @@ public class WatchManager { } private void updateTimerState(boolean watchEnabled, boolean backgroundEnabled, boolean invokeLoadNow) { - Logger.d(TAG, "updateTimerState watchEnabled=" + watchEnabled + " backgroundEnabled=" + backgroundEnabled + " invokeLoadNow=" + invokeLoadNow + " foreground=" + ChanApplication.getInstance().getApplicationInForeground()); + Logger.d(TAG, "updateTimerState watchEnabled=" + watchEnabled + " backgroundEnabled=" + backgroundEnabled + " invokeLoadNow=" + invokeLoadNow + " foreground=" + Chan.getInstance().getApplicationInForeground()); if (watchEnabled) { - if (ChanApplication.getInstance().getApplicationInForeground()) { + if (Chan.getInstance().getApplicationInForeground()) { setTimer(invokeLoadNow ? 1 : FOREGROUND_TIME); } else { if (backgroundEnabled) { diff --git a/Clover/app/src/main/java/org/floens/chan/core/model/Loadable.java b/Clover/app/src/main/java/org/floens/chan/core/model/Loadable.java index a20b8c23..95e44fd1 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/model/Loadable.java +++ b/Clover/app/src/main/java/org/floens/chan/core/model/Loadable.java @@ -57,22 +57,14 @@ public class Loadable { public Loadable() { } - /** - * Quick constructor for a board loadable. - * - * @param board - */ public Loadable(String board) { - mode = Mode.BOARD; + mode = Mode.CATALOG; this.board = board; - no = 0; + this.no = 0; } /** * Quick constructor for a thread loadable. - * - * @param board - * @param no */ public Loadable(String board, int no) { mode = Mode.THREAD; @@ -82,10 +74,6 @@ public class Loadable { /** * Quick constructor for a thread loadable with an title. - * - * @param board - * @param no - * @param title */ public Loadable(String board, int no, String title) { mode = Mode.THREAD; @@ -115,10 +103,6 @@ public class Loadable { return result; } - public boolean isBoardMode() { - return mode == Mode.BOARD; - } - public boolean isThreadMode() { return mode == Mode.THREAD; } @@ -127,26 +111,6 @@ public class Loadable { return mode == Mode.CATALOG; } - public void readFromBundle(Context context, Bundle bundle) { - String p = context.getPackageName(); - mode = bundle.getInt(p + ".mode", Mode.INVALID); - board = bundle.getString(p + ".board", ""); - no = bundle.getInt(p + ".no", -1); - title = bundle.getString(p + ".subject", ""); - listViewIndex = bundle.getInt(p + ".listViewIndex"); - listViewTop = bundle.getInt(p + ".listViewTop"); - } - - public void writeToBundle(Context context, Bundle bundle) { - String p = context.getPackageName(); - bundle.putInt(p + ".mode", mode); - bundle.putString(p + ".board", board); - bundle.putInt(p + ".no", no); - bundle.putString(p + ".subject", title); - bundle.putInt(p + ".listViewIndex", listViewIndex); - bundle.putInt(p + ".listViewTop", listViewTop); - } - public void readFromBundle(Context context, String tag, Bundle bundle) { String p = context.getPackageName(); mode = bundle.getInt(p + "." + tag + ".mode", Mode.INVALID); diff --git a/Clover/app/src/main/java/org/floens/chan/core/model/Post.java b/Clover/app/src/main/java/org/floens/chan/core/model/Post.java index fb355c02..65e31e93 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/model/Post.java +++ b/Clover/app/src/main/java/org/floens/chan/core/model/Post.java @@ -20,7 +20,7 @@ package org.floens.chan.core.model; import android.text.SpannableString; import android.text.TextUtils; -import org.floens.chan.ChanApplication; +import org.floens.chan.Chan; import org.floens.chan.chan.ChanUrls; import org.floens.chan.core.loader.ChanParser; import org.jsoup.parser.Parser; @@ -131,7 +131,7 @@ public class Post { filename = Parser.unescapeEntities(filename, false); if (spoiler) { - Board b = ChanApplication.getBoardManager().getBoardByValue(board); + Board b = Chan.getBoardManager().getBoardByValue(board); if (b != null && b.customSpoilers >= 0) { thumbnailUrl = ChanUrls.getCustomSpoilerUrl(board, random.nextInt(b.customSpoilers) + 1); } else { @@ -143,7 +143,7 @@ public class Post { } if (!TextUtils.isEmpty(country)) { - Board b = ChanApplication.getBoardManager().getBoardByValue(board); + Board b = Chan.getBoardManager().getBoardByValue(board); countryUrl = b.trollFlags ? ChanUrls.getTrollCountryFlagUrl(country) : ChanUrls.getCountryFlagUrl(country); } diff --git a/Clover/app/src/main/java/org/floens/chan/core/model/PostImage.java b/Clover/app/src/main/java/org/floens/chan/core/model/PostImage.java index 9bb03b4b..2de647b1 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/model/PostImage.java +++ b/Clover/app/src/main/java/org/floens/chan/core/model/PostImage.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.core.model; public class PostImage { diff --git a/Clover/app/src/main/java/org/floens/chan/core/net/ByteArrayRequest.java b/Clover/app/src/main/java/org/floens/chan/core/net/ByteArrayRequest.java deleted file mode 100644 index 15fffacd..00000000 --- a/Clover/app/src/main/java/org/floens/chan/core/net/ByteArrayRequest.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Clover - 4chan browser https://github.com/Floens/Clover/ - * Copyright (C) 2014 Floens - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.floens.chan.core.net; - -import com.android.volley.NetworkResponse; -import com.android.volley.Request; -import com.android.volley.Response; -import com.android.volley.Response.ErrorListener; -import com.android.volley.Response.Listener; - -/** - * Request a plain byte[] Warning: no caching! - */ -public class ByteArrayRequest extends Request { - protected final Listener listener; - - public ByteArrayRequest(String url, Listener listener, ErrorListener errorListener) { - super(Method.GET, url, errorListener); - - this.listener = listener; - } - - @Override - protected void deliverResponse(byte[] response) { - listener.onResponse(response); - } - - @Override - protected Response parseNetworkResponse(NetworkResponse response) { - return Response.success(response.data, null); - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/core/net/ChanReaderRequest.java b/Clover/app/src/main/java/org/floens/chan/core/net/ChanReaderRequest.java index e8e4e27a..6ca1f964 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/net/ChanReaderRequest.java +++ b/Clover/app/src/main/java/org/floens/chan/core/net/ChanReaderRequest.java @@ -22,7 +22,7 @@ import android.util.JsonReader; import com.android.volley.Response.ErrorListener; import com.android.volley.Response.Listener; -import org.floens.chan.ChanApplication; +import org.floens.chan.Chan; import org.floens.chan.chan.ChanUrls; import org.floens.chan.core.model.Loadable; import org.floens.chan.core.model.Post; @@ -44,9 +44,7 @@ public class ChanReaderRequest extends JsonReaderRequest> { public static ChanReaderRequest newInstance(Loadable loadable, List cached, Listener> listener, ErrorListener errorListener) { String url; - if (loadable.isBoardMode()) { - url = ChanUrls.getPageUrl(loadable.board, loadable.no); - } else if (loadable.isThreadMode()) { + if (loadable.isThreadMode()) { url = ChanUrls.getThreadUrl(loadable.board, loadable.no); } else if (loadable.isCatalogMode()) { url = ChanUrls.getCatalogUrl(loadable.board); @@ -72,9 +70,7 @@ public class ChanReaderRequest extends JsonReaderRequest> { public List readJson(JsonReader reader) throws Exception { List list; - if (loadable.isBoardMode()) { - list = loadBoard(reader); - } else if (loadable.isThreadMode()) { + if (loadable.isThreadMode()) { list = loadThread(reader); } else if (loadable.isCatalogMode()) { list = loadCatalog(reader); @@ -177,7 +173,7 @@ public class ChanReaderRequest extends JsonReaderRequest> { } for (Post post : totalList) { - post.isSavedReply = ChanApplication.getDatabaseManager().isSavedReply(post.board, post.no); + post.isSavedReply = Chan.getDatabaseManager().isSavedReply(post.board, post.no); } return totalList; @@ -207,44 +203,6 @@ public class ChanReaderRequest extends JsonReaderRequest> { return list; } - private List loadBoard(JsonReader reader) throws Exception { - ArrayList list = new ArrayList<>(); - - reader.beginObject(); // Threads array - - if (reader.nextName().equals("threads")) { - reader.beginArray(); - - while (reader.hasNext()) { - reader.beginObject(); // Thread object - - if (reader.nextName().equals("posts")) { - reader.beginArray(); - - list.add(readPostObject(reader)); - - // Only consume one post - while (reader.hasNext()) - reader.skipValue(); - - reader.endArray(); - } else { - reader.skipValue(); - } - - reader.endObject(); - } - - reader.endArray(); - } else { - reader.skipValue(); - } - - reader.endObject(); - - return list; - } - private List loadCatalog(JsonReader reader) throws Exception { ArrayList list = new ArrayList<>(); diff --git a/Clover/app/src/main/java/org/floens/chan/core/net/FileRequest.java b/Clover/app/src/main/java/org/floens/chan/core/net/FileRequest.java deleted file mode 100644 index b3421aa7..00000000 --- a/Clover/app/src/main/java/org/floens/chan/core/net/FileRequest.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Clover - 4chan browser https://github.com/Floens/Clover/ - * Copyright (C) 2014 Floens - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.floens.chan.core.net; - -import com.android.volley.NetworkResponse; -import com.android.volley.Request; -import com.android.volley.Response; -import com.android.volley.Response.ErrorListener; -import com.android.volley.Response.Listener; -import com.android.volley.toolbox.DiskBasedCache; -import com.android.volley.toolbox.HttpHeaderParser; - -import org.floens.chan.ChanApplication; - -import java.io.File; - -public class FileRequest extends Request { - protected final Listener listener; - - public FileRequest(String url, Listener listener, ErrorListener errorListener) { - super(Method.GET, url, errorListener); - this.listener = listener; - - setShouldCache(true); - } - - @Override - protected Response parseNetworkResponse(NetworkResponse response) { - return Response.success(null, HttpHeaderParser.parseCacheHeaders(response)); - } - - @Override - protected void deliverResponse(Void response) { - DiskBasedCache cache = (DiskBasedCache) ChanApplication.getVolleyRequestQueue().getCache(); - File file = cache.getFileForKey(getCacheKey()); - - if (file.exists()) { - listener.onResponse(file); - } else { - listener.onResponse(null); - } - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/core/net/JsonReaderRequest.java b/Clover/app/src/main/java/org/floens/chan/core/net/JsonReaderRequest.java index 095e7636..f32e1032 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/net/JsonReaderRequest.java +++ b/Clover/app/src/main/java/org/floens/chan/core/net/JsonReaderRequest.java @@ -27,8 +27,9 @@ import com.android.volley.Response.Listener; import com.android.volley.VolleyError; import com.android.volley.toolbox.HttpHeaderParser; +import org.floens.chan.utils.IOUtils; + import java.io.ByteArrayInputStream; -import java.io.IOException; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; @@ -65,13 +66,7 @@ public abstract class JsonReaderRequest extends Request { exception = e; } - if (reader != null) { - try { - reader.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } + IOUtils.closeQuietly(reader); if (read == null) { if (exception != null) { diff --git a/Clover/app/src/main/java/org/floens/chan/core/presenter/ImageViewerPresenter.java b/Clover/app/src/main/java/org/floens/chan/core/presenter/ImageViewerPresenter.java index 7b7c8803..b8237af0 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/presenter/ImageViewerPresenter.java +++ b/Clover/app/src/main/java/org/floens/chan/core/presenter/ImageViewerPresenter.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.core.presenter; import android.support.v4.view.ViewPager; diff --git a/Clover/app/src/main/java/org/floens/chan/core/presenter/ReplyPresenter.java b/Clover/app/src/main/java/org/floens/chan/core/presenter/ReplyPresenter.java index 03abce65..9756ebb6 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/presenter/ReplyPresenter.java +++ b/Clover/app/src/main/java/org/floens/chan/core/presenter/ReplyPresenter.java @@ -1,8 +1,25 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.core.presenter; import android.text.TextUtils; -import org.floens.chan.ChanApplication; +import org.floens.chan.Chan; import org.floens.chan.R; import org.floens.chan.chan.ChanUrls; import org.floens.chan.core.manager.BoardManager; @@ -55,10 +72,10 @@ public class ReplyPresenter implements ReplyManager.FileListener, ReplyManager.H public ReplyPresenter(ReplyPresenterCallback callback) { this.callback = callback; - replyManager = ChanApplication.getReplyManager(); - boardManager = ChanApplication.getBoardManager(); - watchManager = ChanApplication.getWatchManager(); - databaseManager = ChanApplication.getDatabaseManager(); + replyManager = Chan.getReplyManager(); + boardManager = Chan.getBoardManager(); + watchManager = Chan.getWatchManager(); + databaseManager = Chan.getDatabaseManager(); } public void bindLoadable(Loadable loadable) { @@ -144,7 +161,7 @@ public class ReplyPresenter implements ReplyManager.FileListener, ReplyManager.H } previewOpen = false; } else { - ChanApplication.getReplyManager().pickFile(this); + Chan.getReplyManager().pickFile(this); pickingFile = true; } } @@ -313,7 +330,7 @@ public class ReplyPresenter implements ReplyManager.FileListener, ReplyManager.H String baseUrl = loadable.isThreadMode() ? ChanUrls.getThreadUrlDesktop(loadable.board, loadable.no) : ChanUrls.getBoardUrlDesktop(loadable.board); - callback.initCaptcha(baseUrl, ChanUrls.getCaptchaSiteKey(), ChanApplication.getInstance().getUserAgent(), this); + callback.initCaptcha(baseUrl, ChanUrls.getCaptchaSiteKey(), Chan.getInstance().getUserAgent(), this); } break; } diff --git a/Clover/app/src/main/java/org/floens/chan/core/presenter/ThreadPresenter.java b/Clover/app/src/main/java/org/floens/chan/core/presenter/ThreadPresenter.java index 54e6b206..f0e65ee5 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/presenter/ThreadPresenter.java +++ b/Clover/app/src/main/java/org/floens/chan/core/presenter/ThreadPresenter.java @@ -21,7 +21,7 @@ import android.text.TextUtils; import com.android.volley.VolleyError; -import org.floens.chan.ChanApplication; +import org.floens.chan.Chan; import org.floens.chan.R; import org.floens.chan.chan.ChanUrls; import org.floens.chan.core.loader.ChanLoader; @@ -72,8 +72,8 @@ public class ThreadPresenter implements ChanLoader.ChanLoaderCallback, PostAdapt public ThreadPresenter(ThreadPresenterCallback threadPresenterCallback) { this.threadPresenterCallback = threadPresenterCallback; - watchManager = ChanApplication.getWatchManager(); - databaseManager = ChanApplication.getDatabaseManager(); + watchManager = Chan.getWatchManager(); + databaseManager = Chan.getDatabaseManager(); } public void bindLoadable(Loadable loadable) { @@ -287,7 +287,7 @@ public class ThreadPresenter implements ChanLoader.ChanLoaderCallback, PostAdapt menu.add(new FloatingMenuItem(POST_OPTION_DELETE, R.string.delete)); } - if (ChanSettings.getDeveloper()) { + if (ChanSettings.developer.get()) { menu.add(new FloatingMenuItem(POST_OPTION_SAVE, "Save")); } } diff --git a/Clover/app/src/main/java/org/floens/chan/core/reply/HttpCall.java b/Clover/app/src/main/java/org/floens/chan/core/reply/HttpCall.java index fb359b57..c3d67922 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/reply/HttpCall.java +++ b/Clover/app/src/main/java/org/floens/chan/core/reply/HttpCall.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.core.reply; import com.squareup.okhttp.Callback; diff --git a/Clover/app/src/main/java/org/floens/chan/core/reply/ReplyHttpCall.java b/Clover/app/src/main/java/org/floens/chan/core/reply/ReplyHttpCall.java index 21642ac2..8fc369ee 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/reply/ReplyHttpCall.java +++ b/Clover/app/src/main/java/org/floens/chan/core/reply/ReplyHttpCall.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.core.reply; import android.text.TextUtils; diff --git a/Clover/app/src/main/java/org/floens/chan/core/reply/ReplyManager.java b/Clover/app/src/main/java/org/floens/chan/core/reply/ReplyManager.java index 533c801e..7468d996 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/reply/ReplyManager.java +++ b/Clover/app/src/main/java/org/floens/chan/core/reply/ReplyManager.java @@ -19,18 +19,14 @@ package org.floens.chan.core.reply; import android.content.Context; import android.content.Intent; -import android.text.TextUtils; import com.squareup.okhttp.Callback; import com.squareup.okhttp.FormEncodingBuilder; -import com.squareup.okhttp.MediaType; -import com.squareup.okhttp.MultipartBuilder; import com.squareup.okhttp.OkHttpClient; import com.squareup.okhttp.Request; -import com.squareup.okhttp.RequestBody; import com.squareup.okhttp.Response; -import org.floens.chan.ChanApplication; +import org.floens.chan.Chan; import org.floens.chan.R; import org.floens.chan.chan.ChanUrls; import org.floens.chan.core.model.Loadable; @@ -38,18 +34,14 @@ import org.floens.chan.core.model.Reply; import org.floens.chan.core.model.SavedReply; import org.floens.chan.ui.activity.ImagePickActivity; import org.floens.chan.utils.AndroidUtils; -import org.floens.chan.utils.Logger; import java.io.File; import java.io.IOException; import java.net.HttpCookie; import java.util.HashMap; import java.util.List; -import java.util.Locale; import java.util.Map; -import java.util.Random; import java.util.concurrent.TimeUnit; -import java.util.regex.Matcher; import java.util.regex.Pattern; /** @@ -63,7 +55,6 @@ public class ReplyManager { private final Context context; private FileListener fileListener; - private final Random random = new Random(); private OkHttpClient client; private Map drafts = new HashMap<>(); @@ -169,7 +160,7 @@ public class ReplyManager { public void onFailure(Request request, IOException e) { final PassResponse res = new PassResponse(); res.isError = true; - res.message = context.getString(R.string.pass_error); + res.message = context.getString(R.string.setting_pass_error); runUI(new Runnable() { public void run() { passListener.onResponse(res); @@ -317,131 +308,6 @@ public class ReplyManager { public String responseData = ""; } - public void postReply(Reply reply, ReplyListener replyListener) { - if (reply.usePass) { - postReplyInternal(reply, replyListener, null); - } else { - postReplyInternal(reply, replyListener, reply.captchaResponse); - } - } - - private void postReplyInternal(final Reply reply, final ReplyListener replyListener, String captchaHash) { -// reply.password = Long.toHexString(random.nextLong()); - - MultipartBuilder formBuilder = new MultipartBuilder(); - formBuilder.type(MultipartBuilder.FORM); - - formBuilder.addFormDataPart("mode", "regist"); -// formBuilder.addFormDataPart("pwd", reply.password); - - if (reply.resto >= 0) { - formBuilder.addFormDataPart("resto", String.valueOf(reply.resto)); - } - - formBuilder.addFormDataPart("name", reply.name); - formBuilder.addFormDataPart("email", reply.options); - - if (reply.resto >= 0 && !TextUtils.isEmpty(reply.subject)) { - formBuilder.addFormDataPart("sub", reply.subject); - } - - formBuilder.addFormDataPart("com", reply.comment); - - if (captchaHash != null) { - formBuilder.addFormDataPart("g-recaptcha-response", captchaHash); - } - - if (reply.file != null) { - formBuilder.addFormDataPart("upfile", reply.fileName, RequestBody.create( - MediaType.parse("application/octet-stream"), reply.file - )); - } - - if (reply.spoilerImage) { - formBuilder.addFormDataPart("spoiler", "on"); - } - - Request.Builder request = new Request.Builder() - .url(ChanUrls.getReplyUrl(reply.board)) - .post(formBuilder.build()); - - if (reply.usePass) { - request.addHeader("Cookie", "pass_id=" + reply.passId); - } - - makeOkHttpCall(request, new Callback() { - @Override - public void onFailure(Request request, IOException e) { - final ReplyResponse res = new ReplyResponse(); - res.isNetworkError = true; - - runUI(new Runnable() { - public void run() { - replyListener.onResponse(res); - } - }); - } - - @Override - public void onResponse(Response response) throws IOException { - final ReplyResponse res = new ReplyResponse(); - if (response.isSuccessful()) { - onReplyPosted(response.body().string(), reply, res); - response.body().close(); - } else { - res.isNetworkError = true; - } - - runUI(new Runnable() { - public void run() { - replyListener.onResponse(res); - } - }); - } - }); - } - - private ReplyResponse onReplyPosted(String responseString, Reply reply, ReplyResponse res) { - res.responseData = responseString; - - if (res.responseData.contains("No file selected")) { - res.isUserError = true; - res.isFileError = true; - } else if (res.responseData.contains("You forgot to solve the CAPTCHA") || res.responseData.contains("You seem to have mistyped the CAPTCHA")) { - res.isUserError = true; - res.isCaptchaError = true; - } else if (res.responseData.toLowerCase(Locale.ENGLISH).contains("post successful")) { - res.isSuccessful = true; - - Matcher matcher = POST_THREAD_NO_PATTERN.matcher(res.responseData); - int threadNo = -1; - int no = -1; - if (matcher.find()) { - try { - threadNo = Integer.parseInt(matcher.group(1)); - no = Integer.parseInt(matcher.group(2)); - } catch (NumberFormatException err) { - err.printStackTrace(); - } - } - - if (threadNo >= 0 && no >= 0) { - SavedReply savedReply = new SavedReply(); - savedReply.board = reply.board; - savedReply.no = no; -// savedReply.password = reply.password; - - ChanApplication.getDatabaseManager().saveReply(savedReply); - - res.threadNo = threadNo; - res.no = no; - } else { - Logger.w(TAG, "No thread & no in the response"); - } - } - return res; - } - public void makeHttpCall(HttpCall httpCall, HttpCallback callback) { //noinspection unchecked httpCall.setCallback(callback); @@ -450,7 +316,7 @@ public class ReplyManager { httpCall.setup(requestBuilder); - requestBuilder.header("User-Agent", ChanApplication.getInstance().getUserAgent()); + requestBuilder.header("User-Agent", Chan.getInstance().getUserAgent()); Request request = requestBuilder.build(); client.newCall(request).enqueue(httpCall); @@ -463,7 +329,7 @@ public class ReplyManager { } private void makeOkHttpCall(Request.Builder requestBuilder, Callback callback) { - requestBuilder.header("User-Agent", ChanApplication.getInstance().getUserAgent()); + requestBuilder.header("User-Agent", Chan.getInstance().getUserAgent()); Request request = requestBuilder.build(); client.newCall(request).enqueue(callback); } @@ -471,51 +337,4 @@ public class ReplyManager { private void runUI(Runnable runnable) { AndroidUtils.runOnUiThread(runnable); } - - public interface ReplyListener { - void onResponse(ReplyResponse response); - } - - public static class ReplyResponse { - /** - * No response from server. - */ - public boolean isNetworkError = false; - - /** - * Some user error, like no file or captcha wrong. - */ - public boolean isUserError = false; - - /** - * The userError was an fileError - */ - public boolean isFileError = false; - - /** - * The userError was an captchaError - */ - public boolean isCaptchaError = false; - - /** - * Received 'post successful' - */ - public boolean isSuccessful = false; - - /** - * Raw html from the response. Used to set html in an WebView to the - * client, when the error was not recognized by Clover. - */ - public String responseData = ""; - - /** - * The no the post has - */ - public int no = -1; - - /** - * The thread no the post has - */ - public int threadNo = -1; - } } diff --git a/Clover/app/src/main/java/org/floens/chan/core/settings/BooleanSetting.java b/Clover/app/src/main/java/org/floens/chan/core/settings/BooleanSetting.java index 31e82dea..fa17f65c 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/settings/BooleanSetting.java +++ b/Clover/app/src/main/java/org/floens/chan/core/settings/BooleanSetting.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.core.settings; import android.content.SharedPreferences; diff --git a/Clover/app/src/main/java/org/floens/chan/core/settings/ChanSettings.java b/Clover/app/src/main/java/org/floens/chan/core/settings/ChanSettings.java index 8ea4078f..3763cb1a 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/settings/ChanSettings.java +++ b/Clover/app/src/main/java/org/floens/chan/core/settings/ChanSettings.java @@ -20,7 +20,7 @@ package org.floens.chan.core.settings; import android.content.SharedPreferences; import android.os.Environment; -import org.floens.chan.ChanApplication; +import org.floens.chan.Chan; import org.floens.chan.chan.ChanUrls; import org.floens.chan.utils.AndroidUtils; @@ -98,217 +98,32 @@ public class ChanSettings { watchEnabled = new BooleanSetting(p, "preference_watch_enabled", false, new Setting.SettingCallback() { @Override public void onValueChange(Setting setting, Boolean value) { - ChanApplication.getWatchManager().onWatchEnabledChanged(value); + Chan.getWatchManager().onWatchEnabledChanged(value); } }); watchCountdown = new BooleanSetting(p, "preference_watch_countdown", false); watchBackground = new BooleanSetting(p, "preference_watch_background_enabled", false, new Setting.SettingCallback() { @Override public void onValueChange(Setting setting, Boolean value) { - ChanApplication.getWatchManager().onBackgroundWatchingChanged(value); + Chan.getWatchManager().onBackgroundWatchingChanged(value); } }); watchBackgroundTimeout = new StringSetting(p, "preference_watch_background_timeout", "60"); watchNotifyMode = new StringSetting(p, "preference_watch_notify_mode", "all"); - watchSound = new StringSetting(p, "preference_watch_sound", "all"); + watchSound = new StringSetting(p, "preference_watch_sound", "quotes"); watchLed = new StringSetting(p, "preference_watch_led", "ffffffff"); passToken = new StringSetting(p, "preference_pass_token", ""); passPin = new StringSetting(p, "preference_pass_pin", ""); passId = new StringSetting(p, "preference_pass_id", ""); - } - private static SharedPreferences p() { - return AndroidUtils.getPreferences(); + // Old (but possibly still in some users phone) + // preference_board_view_mode default "list" + // preference_board_editor_filler default false + // preference_pass_enabled default false } public static boolean passLoggedIn() { return passId.get().length() > 0; } - - public static boolean getOpenLinkConfirmation() { - return p().getBoolean("preference_open_link_confirmation", true); - } - - public static String getDefaultName() { - return p().getString("preference_default_name", ""); - } - - public static boolean getPinOnPost() { - return p().getBoolean("preference_pin_on_post", false); - } - - public static boolean getDeveloper() { - return p().getBoolean("preference_developer", false); - } - - public static void setDeveloper(boolean developer) { - p().edit().putBoolean("preference_developer", developer).commit(); - } - - public static File getImageSaveDirectory() { - String path = p().getString("preference_image_save_location", null); - File file; - if (path == null) { - file = new File(Environment.getExternalStorageDirectory() + File.separator + "Clover"); - } else { - file = new File(path); - } - - return file; - } - - public static void setImageSaveDirectory(File file) { - p().edit().putString("preference_image_save_location", file.getAbsolutePath()).commit(); - } - - public static boolean getImageSaveOriginalFilename() { - return p().getBoolean("preference_image_save_original", false); - } - - public static boolean getImageShareUrl() { - return p().getBoolean("preference_image_share_url", false); - } - - public static boolean getWatchEnabled() { - return p().getBoolean("preference_watch_enabled", false); - } - - /** - * This also calls updateRunningState on the PinnedService to start/stop the - * service as needed. - * - * @param enabled - */ - public static void setWatchEnabled(boolean enabled) { - if (getWatchEnabled() != enabled) { - p().edit().putBoolean("preference_watch_enabled", enabled).commit(); - ChanApplication.getWatchManager().onWatchEnabledChanged(enabled); - } - } - - public static boolean getWatchCountdownVisibleEnabled() { - return p().getBoolean("preference_watch_countdown", false); - } - - public static boolean getWatchBackgroundEnabled() { - return p().getBoolean("preference_watch_background_enabled", false); - } - - public static int getWatchBackgroundTimeout() { - String number = p().getString("preference_watch_background_timeout", "60"); - return Integer.parseInt(number); - } - - public static String getWatchNotifyMode() { - return p().getString("preference_watch_notify_mode", "all"); - } - - public static String getWatchSound() { - return p().getString("preference_watch_sound", "quotes"); - } - - public static long getWatchLed() { - String raw = p().getString("preference_watch_led", "ffffffff"); - return Long.parseLong(raw, 16); - } - - public static boolean getVideoAutoPlay() { - return getImageAutoLoad() && !getVideoExternal() && p().getBoolean("preference_autoplay", false); - } - - public static boolean getThreadAutoRefresh() { - return p().getBoolean("preference_auto_refresh_thread", true); - } - - public static boolean getImageAutoLoad() { - return p().getBoolean("preference_image_auto_load", true); - } - - public static boolean getPassEnabled() { - return p().getBoolean("preference_pass_enabled", false); - } - - public static void setPassEnabled(boolean enabled) { - if (getPassEnabled() != enabled) { - p().edit().putBoolean("preference_pass_enabled", enabled).commit(); - } - } - - public static String getPassToken() { - return p().getString("preference_pass_token", ""); - } - - public static String getPassPin() { - return p().getString("preference_pass_pin", ""); - } - - public static void setPassId(String id) { - p().edit().putString("preference_pass_id", id).commit(); - } - - public static String getPassId() { - return p().getString("preference_pass_id", ""); - } - - public static String getTheme() { - return p().getString("preference_theme", "light"); - } - - public static boolean getForcePhoneLayout() { - return p().getBoolean("preference_force_phone_layout", false); - } - - public static boolean getBoardEditorFillerEnabled() { - return p().getBoolean("preference_board_editor_filler", false); - } - - public static boolean setBoardEditorFillerEnabled(boolean enabled) { - return p().edit().putBoolean("preference_board_editor_filler", enabled).commit(); - } - - public static String getBoardViewMode() { - return p().getString("preference_board_view_mode", "list"); - } - - public static void setBoardViewMode(String mode) { - p().edit().putString("preference_board_view_mode", mode).commit(); - } - - public static boolean getAnonymize() { - return p().getBoolean("preference_anonymize", false); - } - - public static boolean getAnonymizeIds() { - return p().getBoolean("preference_anonymize_ids", false); - } - - public static boolean getReplyButtonsBottom() { - return p().getBoolean("preference_buttons_bottom", false); - } - - public static String getBoardMode() { - return p().getString("preference_board_mode", "catalog"); - } - - public static boolean getVideoErrorIgnore() { - return p().getBoolean("preference_video_error_ignore", false); - } - - public static void setVideoErrorIgnore(boolean show) { - p().edit().putBoolean("preference_video_error_ignore", show).commit(); - } - - public static boolean getVideoExternal() { - return p().getBoolean("preference_video_external", false); - } - - public static int getFontSize() { - String font = p().getString("preference_font", null); - return font == null ? 14 : Integer.parseInt(font); - } - - public static boolean getNetworkHttps() { - return p().getBoolean("preference_network_https", true); - } } diff --git a/Clover/app/src/main/java/org/floens/chan/core/settings/Setting.java b/Clover/app/src/main/java/org/floens/chan/core/settings/Setting.java index e7c2c4f7..a2bf9cde 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/settings/Setting.java +++ b/Clover/app/src/main/java/org/floens/chan/core/settings/Setting.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.core.settings; import android.content.SharedPreferences; diff --git a/Clover/app/src/main/java/org/floens/chan/core/settings/StringSetting.java b/Clover/app/src/main/java/org/floens/chan/core/settings/StringSetting.java index df699062..bd507c82 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/settings/StringSetting.java +++ b/Clover/app/src/main/java/org/floens/chan/core/settings/StringSetting.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.core.settings; import android.content.SharedPreferences; diff --git a/Clover/app/src/main/java/org/floens/chan/core/watch/PinWatcher.java b/Clover/app/src/main/java/org/floens/chan/core/watch/PinWatcher.java index cef5a8d8..56712a92 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/watch/PinWatcher.java +++ b/Clover/app/src/main/java/org/floens/chan/core/watch/PinWatcher.java @@ -19,7 +19,7 @@ package org.floens.chan.core.watch; import com.android.volley.VolleyError; -import org.floens.chan.ChanApplication; +import org.floens.chan.Chan; import org.floens.chan.core.loader.ChanLoader; import org.floens.chan.core.loader.LoaderPool; import org.floens.chan.core.model.ChanThread; @@ -122,7 +122,7 @@ public class PinWatcher implements ChanLoader.ChanLoaderCallback { AndroidUtils.runOnUiThread(new Runnable() { @Override public void run() { - ChanApplication.getWatchManager().onPinsChanged(); + Chan.getWatchManager().onPinsChanged(); } }); } @@ -195,7 +195,7 @@ public class PinWatcher implements ChanLoader.ChanLoaderCallback { AndroidUtils.runOnUiThread(new Runnable() { @Override public void run() { - ChanApplication.getWatchManager().pinWatcherUpdated(pin); + Chan.getWatchManager().pinWatcherUpdated(pin); } }); } diff --git a/Clover/app/src/main/java/org/floens/chan/test/TestActivity.java b/Clover/app/src/main/java/org/floens/chan/test/TestActivity.java index 136a8013..d34ed167 100644 --- a/Clover/app/src/main/java/org/floens/chan/test/TestActivity.java +++ b/Clover/app/src/main/java/org/floens/chan/test/TestActivity.java @@ -27,12 +27,12 @@ import android.widget.LinearLayout; import com.android.volley.VolleyError; -import org.floens.chan.ChanApplication; +import org.floens.chan.Chan; +import org.floens.chan.core.cache.FileCache; import org.floens.chan.core.loader.ChanLoader; import org.floens.chan.core.model.ChanThread; import org.floens.chan.core.model.Loadable; import org.floens.chan.core.model.Post; -import org.floens.chan.utils.FileCache; import org.floens.chan.utils.Logger; import org.floens.chan.utils.ThemeHelper; @@ -90,7 +90,7 @@ public class TestActivity extends Activity implements View.OnClickListener { File cacheDir = getExternalCacheDir() != null ? getExternalCacheDir() : getCacheDir(); File fileCacheDir = new File(cacheDir, "filecache"); - fileCache = new FileCache(fileCacheDir, 50 * 1024 * 1024, ChanApplication.getInstance().getUserAgent()); + fileCache = new FileCache(fileCacheDir, 50 * 1024 * 1024, Chan.getInstance().getUserAgent()); } @Override diff --git a/Clover/app/src/main/java/org/floens/chan/ui/ThemeActivity.java b/Clover/app/src/main/java/org/floens/chan/ui/ThemeActivity.java deleted file mode 100644 index 8e987953..00000000 --- a/Clover/app/src/main/java/org/floens/chan/ui/ThemeActivity.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Clover - 4chan browser https://github.com/Floens/Clover/ - * Copyright (C) 2014 Floens - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.floens.chan.ui; - -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; -import android.view.MenuItem; - -import org.floens.chan.R; -import org.floens.chan.utils.ThemeHelper; - -public class ThemeActivity extends AppCompatActivity { - private Toolbar toolbar; - - public void setTheme() { - setTheme(ThemeHelper.getInstance().getTheme().resValue); - } - - public void setToolbar() { - toolbar = (Toolbar) findViewById(R.id.toolbar); - setSupportActionBar(toolbar); - } - - @Override - public boolean onOptionsItemSelected(final MenuItem item) { - if (item.getItemId() == android.R.id.home) { - finish(); - return true; - } else { - return super.onOptionsItemSelected(item); - } - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/activity/AboutActivity.java b/Clover/app/src/main/java/org/floens/chan/ui/activity/AboutActivity.java deleted file mode 100644 index 10f4c897..00000000 --- a/Clover/app/src/main/java/org/floens/chan/ui/activity/AboutActivity.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Clover - 4chan browser https://github.com/Floens/Clover/ - * Copyright (C) 2014 Floens - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.floens.chan.ui.activity; - -import android.os.Bundle; -import android.webkit.WebView; - -import org.floens.chan.R; -import org.floens.chan.ui.ThemeActivity; - -public class AboutActivity extends ThemeActivity { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setTheme(); - setContentView(R.layout.toolbar_activity); - setToolbar(); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - - WebView webView = new WebView(this); - webView.loadUrl("file:///android_asset/html/licenses.html"); - - setContentView(webView); - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/activity/AdvancedSettingsActivity.java b/Clover/app/src/main/java/org/floens/chan/ui/activity/AdvancedSettingsActivity.java deleted file mode 100644 index 3bf2cab9..00000000 --- a/Clover/app/src/main/java/org/floens/chan/ui/activity/AdvancedSettingsActivity.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Clover - 4chan browser https://github.com/Floens/Clover/ - * Copyright (C) 2014 Floens - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.floens.chan.ui.activity; - -import android.os.Bundle; -import android.preference.ListPreference; -import android.preference.Preference; -import android.preference.PreferenceFragment; - -import org.floens.chan.R; -import org.floens.chan.chan.ChanUrls; -import org.floens.chan.core.settings.ChanSettings; -import org.floens.chan.ui.ThemeActivity; -import org.floens.chan.ui.fragment.FolderPickFragment; - -import java.io.File; - -public class AdvancedSettingsActivity extends ThemeActivity { - @Override - protected void onCreate(final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setTheme(); - setContentView(R.layout.toolbar_activity); - setToolbar(); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - - getFragmentManager().beginTransaction().replace(R.id.content, new AdvancedSettingsFragment()).commit(); - } - - public static class AdvancedSettingsFragment extends PreferenceFragment { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - addPreferencesFromResource(R.xml.preference_advanced); - - findPreference("preference_force_phone_layout").setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(final Preference preference, final Object newValue) { - BaseActivity.doRestartOnResume = true; - return true; - } - }); - - findPreference("preference_anonymize").setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(final Preference preference, final Object newValue) { - BaseActivity.doRestartOnResume = true; - return true; - } - }); - - findPreference("preference_anonymize_ids").setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(final Preference preference, final Object newValue) { - BaseActivity.doRestartOnResume = true; - return true; - } - }); - - final ListPreference boardMode = (ListPreference) findPreference("preference_board_mode"); - String currentModeValue = boardMode.getValue(); - if (currentModeValue == null) { - boardMode.setValue((String) boardMode.getEntryValues()[0]); - currentModeValue = boardMode.getValue(); - } - updateSummary(boardMode, currentModeValue); - boardMode.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - updateSummary(boardMode, newValue.toString()); - BaseActivity.doRestartOnResume = true; - return true; - } - }); - - reloadSavePath(); - final Preference saveLocation = findPreference("preference_image_save_location"); - saveLocation.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - File dir = ChanSettings.getImageSaveDirectory(); - dir.mkdirs(); - - FolderPickFragment frag = FolderPickFragment.newInstance(new FolderPickFragment.FolderPickListener() { - @Override - public void folderPicked(File path) { - ChanSettings.setImageSaveDirectory(path); - reloadSavePath(); - } - }, dir); - getActivity().getFragmentManager().beginTransaction().add(frag, null).commit(); - - return true; - } - }); - - findPreference("preference_network_https").setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - ChanUrls.loadScheme((Boolean) newValue); - - return true; - } - }); - } - - private void reloadSavePath() { - Preference saveLocation = findPreference("preference_image_save_location"); - saveLocation.setSummary(ChanSettings.getImageSaveDirectory().getAbsolutePath()); - } - - private void updateSummary(ListPreference list, String value) { - int index = list.findIndexOfValue(value); - list.setSummary(list.getEntries()[index]); - } - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/activity/BaseActivity.java b/Clover/app/src/main/java/org/floens/chan/ui/activity/BaseActivity.java deleted file mode 100644 index b7e8497a..00000000 --- a/Clover/app/src/main/java/org/floens/chan/ui/activity/BaseActivity.java +++ /dev/null @@ -1,384 +0,0 @@ -/* - * Clover - 4chan browser https://github.com/Floens/Clover/ - * Copyright (C) 2014 Floens - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.floens.chan.ui.activity; - -import android.app.AlertDialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.res.TypedArray; -import android.net.Uri; -import android.nfc.NdefMessage; -import android.nfc.NdefRecord; -import android.nfc.NfcAdapter; -import android.os.Bundle; -import android.support.v4.view.GravityCompat; -import android.support.v4.widget.DrawerLayout; -import android.support.v4.widget.SlidingPaneLayout; -import android.support.v4.widget.SlidingPaneLayout.PanelSlideListener; -import android.support.v7.app.ActionBarDrawerToggle; -import android.support.v7.widget.ShareActionProvider; -import android.text.TextUtils; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.AdapterView.OnItemLongClickListener; -import android.widget.EditText; -import android.widget.ListView; - -import org.floens.chan.ChanApplication; -import org.floens.chan.R; -import org.floens.chan.core.model.ChanThread; -import org.floens.chan.core.model.Loadable; -import org.floens.chan.core.model.Pin; -import org.floens.chan.core.model.Post; -import org.floens.chan.ui.ThemeActivity; -import org.floens.chan.ui.adapter.PinnedAdapter; -import org.floens.chan.ui.animation.SwipeDismissListViewTouchListener; -import org.floens.chan.ui.animation.SwipeDismissListViewTouchListener.DismissCallbacks; -import org.floens.chan.utils.AndroidUtils; -import org.floens.chan.utils.ThemeHelper; - -import static org.floens.chan.utils.AndroidUtils.dp; - -public abstract class BaseActivity extends ThemeActivity implements PanelSlideListener { - public static boolean doRestartOnResume = false; - - private final static int ACTION_OPEN_URL = 1; - - protected PinnedAdapter pinnedAdapter; - protected DrawerLayout pinDrawer; - protected ListView pinDrawerView; - protected ActionBarDrawerToggle pinDrawerListener; - - protected SlidingPaneLayout threadPane; - - private String shareUrl; - private ShareActionProvider shareActionProvider; - private Intent pendingShareActionProviderIntent; - - /** - * Called when a post has been clicked in the pinned drawer - * - * @param post - */ - abstract public void openPin(Pin post); - - /** - * Called when a post has been clicked in the listview - * - * @param post - */ - abstract public void onOPClicked(Post post); - - abstract public void onOpenThread(Loadable thread); - - abstract public void onThreadLoaded(ChanThread thread); - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - ThemeHelper.getInstance().reloadPostViewColors(this); - - setContentView(R.layout.activity_base); - - setTheme(); - setToolbar(); - - pinDrawer = (DrawerLayout) findViewById(R.id.drawer_layout); - initDrawer(); - - threadPane = (SlidingPaneLayout) findViewById(R.id.pane_container); - initPane(); - - updateIcon(); - } - - @Override - public void onBackPressed() { - if (pinDrawer.isDrawerOpen(pinDrawerView)) { - pinDrawer.closeDrawer(pinDrawerView); - } else { - super.onBackPressed(); - } - } - - @Override - protected void onDestroy() { - super.onDestroy(); - } - - @Override - protected void onResume() { - super.onResume(); - - if (doRestartOnResume) { - doRestartOnResume = false; - recreate(); - } - } - - private void initPane() { - threadPane.setPanelSlideListener(this); - threadPane.setParallaxDistance(dp(100)); - threadPane.setShadowResource(R.drawable.panel_shadow); - - TypedArray ta = obtainStyledAttributes(null, R.styleable.BoardPane, R.attr.board_pane_style, 0); - int color = ta.getColor(R.styleable.BoardPane_fade_color, 0); - ta.recycle(); - - threadPane.setSliderFadeColor(color); - threadPane.openPane(); - } - - protected void initDrawer() { - if (pinDrawerListener == null) { - return; - } - - pinDrawer.setDrawerListener(pinDrawerListener); - pinDrawer.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START); - - pinDrawerView = (ListView) findViewById(R.id.left_drawer); - - pinnedAdapter = new PinnedAdapter(getSupportActionBar().getThemedContext(), pinDrawerView); // Get the dark theme, not the light one - pinnedAdapter.reload(); - pinDrawerView.setAdapter(pinnedAdapter); - - pinDrawerView.setOnItemClickListener(new OnItemClickListener() { - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - Pin pin = pinnedAdapter.getItem(position); - if (pin == null) - return; - openPin(pin); - } - }); - - pinDrawerView.setOnItemLongClickListener(new OnItemLongClickListener() { - @Override - public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { - Pin post = pinnedAdapter.getItem(position); - if (post == null) - return false; - - onPinLongPress(post); - - return true; - } - }); - - SwipeDismissListViewTouchListener touchListener = new SwipeDismissListViewTouchListener(pinDrawerView, - new DismissCallbacks() { - @Override - public void onDismiss(ListView listView, int[] reverseSortedPositions) { - for (int position : reverseSortedPositions) { - removePin(pinnedAdapter.getItem(position)); - } - } - - @Override - public boolean canDismiss(int position) { - return pinnedAdapter.getItem(position) != null; - } - } - ); - - pinDrawerView.setOnTouchListener(touchListener); - pinDrawerView.setOnScrollListener(touchListener.makeScrollListener()); - pinDrawerView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); - } - - private void updateIcon() { - /*List list = ChanApplication.getWatchManager().getWatchingPins(); - if (list.size() > 0) { - int count = 0; - boolean color = false; - for (Pin p : list) { - count += p.getNewPostCount(); - if (p.getNewQuoteCount() > 0) { - color = true; - } - } - - if (count > 0) { - Drawable icon = BadgeDrawable.get(getResources(), R.drawable.ic_launcher, count, color); - getSupportActionBar().setIcon(icon); - } else { - getSupportActionBar().setIcon(R.drawable.ic_launcher); - } - } else { - getSupportActionBar().setIcon(R.drawable.ic_launcher); - }*/ - } - - public void removePin(Pin pin) { - ChanApplication.getWatchManager().removePin(pin); - } - - public void updatePin(Pin pin) { - ChanApplication.getWatchManager().updatePin(pin); - } - - private void onPinLongPress(final Pin pin) { - new AlertDialog.Builder(this) - .setNegativeButton(R.string.drawer_pinned_delete, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - // Delete pin - removePin(pin); - } - }).setPositiveButton(R.string.drawer_pinned_change_title, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - // Change pin title - final EditText text = new EditText(BaseActivity.this); - text.setSingleLine(); - text.setText(pin.loadable.title); - text.setSelectAllOnFocus(true); - - AlertDialog titleDialog = new AlertDialog.Builder(BaseActivity.this) - .setPositiveButton(R.string.change, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface d, int which) { - String value = text.getText().toString(); - - if (!TextUtils.isEmpty(value)) { - pin.loadable.title = value; - updatePin(pin); - } - } - }).setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface d, int which) { - } - }).setTitle(R.string.drawer_pinned_change_title).setView(text).create(); - - AndroidUtils.requestKeyboardFocus(titleDialog, text); - - titleDialog.show(); - } - }).show(); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.action_settings: - startActivity(new Intent(this, SettingsActivity.class)); - return true; - } - - return super.onOptionsItemSelected(item); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.base, menu); - /*shareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(menu.findItem(R.id.action_share)); - if (pendingShareActionProviderIntent != null) { - shareActionProvider.setShareIntent(pendingShareActionProviderIntent); - pendingShareActionProviderIntent = null; - }*/ - - return true; - } - - @Override - public void onPanelClosed(View view) { - } - - @Override - public void onPanelOpened(View view) { - } - - @Override - public void onPanelSlide(View view, float offset) { - } - - /** - * Set the url that Android Beam and the share action will send. - * - * @param url - */ - public void setShareUrl(String url) { - shareUrl = url; - - NfcAdapter adapter = NfcAdapter.getDefaultAdapter(this); - - if (adapter != null) { - NdefRecord record = null; - try { - record = NdefRecord.createUri(url); - } catch (IllegalArgumentException e) { - e.printStackTrace(); - return; - } - - NdefMessage message = new NdefMessage(new NdefRecord[]{record}); - try { - adapter.setNdefPushMessage(message, this); - } catch (Exception e) { - } - } - - Intent share = new Intent(android.content.Intent.ACTION_SEND); - share.putExtra(android.content.Intent.EXTRA_TEXT, url); - share.setType("text/plain"); - - if (shareActionProvider != null) { - shareActionProvider.setShareIntent(share); - } else { - pendingShareActionProviderIntent = share; - } - } - - public void openInBrowser() { - if (shareUrl != null) { - showUrlOpenPicker(shareUrl); - } - } - - /** - * Let the user choose between all activities that can open the url. This is - * done to prevent "open in browser" opening the url in our own app. - * - * @param url - */ - public void showUrlOpenPicker(String url) { - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setData(Uri.parse(url)); - startActivity(intent); - } - - /** - * Used for showUrlOpenPicker - */ - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - - if (requestCode == ACTION_OPEN_URL && resultCode == RESULT_OK && data != null) { - data.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(data); - } - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/activity/BoardEditor.java b/Clover/app/src/main/java/org/floens/chan/ui/activity/BoardEditor.java deleted file mode 100644 index 20666d98..00000000 --- a/Clover/app/src/main/java/org/floens/chan/ui/activity/BoardEditor.java +++ /dev/null @@ -1,451 +0,0 @@ -/* - * Clover - 4chan browser https://github.com/Floens/Clover/ - * Copyright (C) 2014 Floens - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.floens.chan.ui.activity; - -import android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.graphics.Color; -import android.graphics.Point; -import android.graphics.drawable.ColorDrawable; -import android.os.Bundle; -import android.text.TextUtils; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputMethodManager; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.AutoCompleteTextView; -import android.widget.Filter; -import android.widget.Filterable; -import android.widget.ListView; -import android.widget.TextView; -import android.widget.Toast; - -import com.mobeta.android.dslv.DragSortController; -import com.mobeta.android.dslv.DragSortListView; - -import org.floens.chan.ChanApplication; -import org.floens.chan.R; -import org.floens.chan.core.settings.ChanSettings; -import org.floens.chan.core.manager.BoardManager; -import org.floens.chan.core.model.Board; -import org.floens.chan.ui.animation.SwipeDismissListViewTouchListener; -import org.floens.chan.ui.ThemeActivity; -import org.floens.chan.utils.AndroidUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -public class BoardEditor extends ThemeActivity { - private final BoardManager boardManager = ChanApplication.getBoardManager(); - - private List list; - private DragSortListView listView; - private BoardEditAdapter adapter; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setTheme(); - setContentView(R.layout.toolbar_activity); - setToolbar(); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - - list = boardManager.getSavedBoards(); - - adapter = new BoardEditAdapter(this, 0, list); - - listView = new DragSortListView(this, null); - listView.setAdapter(adapter); - listView.setDivider(new ColorDrawable(Color.TRANSPARENT)); - - final DragSortController controller = new NiceDragSortController(listView, adapter); - - listView.setFloatViewManager(controller); - listView.setOnTouchListener(controller); - listView.setDragEnabled(true); - listView.setDropListener(new DragSortListView.DropListener() { - @Override - public void drop(int from, int to) { - if (from != to) { - Board board = list.remove(from); - list.add(to, board); - adapter.notifyDataSetChanged(); - } - } - }); - - final SwipeDismissListViewTouchListener touchListener = new SwipeDismissListViewTouchListener(listView, - new SwipeDismissListViewTouchListener.DismissCallbacks() { - @Override - public void onDismiss(ListView listView, int[] reverseSortedPositions) { - for (int position : reverseSortedPositions) { - if (position >= 0 && position < adapter.getCount()) { - Board b = adapter.getItem(position); - adapter.remove(b); - b.saved = false; - } - } - - adapter.notifyDataSetChanged(); - } - - @Override - public boolean canDismiss(int position) { - return list.size() > 1; - } - } - ); - - listView.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View view, MotionEvent motionEvent) { - return controller.onTouch(view, motionEvent) - || (!listView.isDragging() && touchListener.onTouch(view, motionEvent)); - } - }); - - listView.setOnScrollListener(touchListener.makeScrollListener()); - - listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { - @Override - public boolean onItemLongClick(AdapterView parent, View view, final int position, long id) { - new AlertDialog.Builder(BoardEditor.this) - .setNegativeButton(R.string.cancel, null) - .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - if (position >= 0 && position < adapter.getCount()) { - Board b = adapter.getItem(position); - adapter.remove(b); - b.saved = false; - adapter.notifyDataSetChanged(); - } - } - }) - .setMessage(R.string.board_delete) - .show(); - return true; - } - }); - - ((ViewGroup) findViewById(R.id.content)).addView(listView); - } - - @Override - protected void onPause() { - super.onPause(); - - if (list.size() > 0) { - // Order - for (int i = 0; i < list.size(); i++) { - list.get(i).order = i; - } - - boardManager.updateSavedBoards(); - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.board_edit, menu); - - menu.findItem(R.id.action_show_filler).setChecked(ChanSettings.getBoardEditorFillerEnabled()); - - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.action_add_board: - showAddBoardDialog(); - return true; - case R.id.action_show_filler: - ChanSettings.setBoardEditorFillerEnabled(!ChanSettings.getBoardEditorFillerEnabled()); - item.setChecked(ChanSettings.getBoardEditorFillerEnabled()); - return true; - case android.R.id.home: - finish(); - return true; - } - - return super.onOptionsItemSelected(item); - } - - private void addBoard(String value) { - value = value.trim(); - value = value.replace("/", ""); - value = value.replace("\\", ""); // what are you doing?! - - // Duplicate - for (Board board : list) { - if (board.value.equals(value)) { - Toast.makeText(this, R.string.board_add_duplicate, Toast.LENGTH_LONG).show(); - - return; - } - } - - // Normal add - List all = ChanApplication.getBoardManager().getAllBoards(); - for (Board board : all) { - if (board.value.equals(value)) { - board.saved = true; - list.add(board); - adapter.notifyDataSetChanged(); - - Toast.makeText(this, getString(R.string.board_add_success) + " " + board.key, Toast.LENGTH_LONG).show(); - - return; - } - } - - // Unknown - new AlertDialog.Builder(this) - .setTitle(R.string.board_add_unknown_title) - .setMessage(getString(R.string.board_add_unknown, value)) - .setPositiveButton(R.string.ok, null) - .show(); - } - - private void showAddBoardDialog() { - final AutoCompleteTextView text = new AutoCompleteTextView(this); - text.setSingleLine(); - - FillAdapter fillAdapter = new FillAdapter(this, 0); - fillAdapter.setEditingList(list); - fillAdapter.setAutoCompleteView(text); - text.setAdapter(fillAdapter); - text.setThreshold(1); - text.setDropDownHeight(ViewGroup.LayoutParams.WRAP_CONTENT); - text.setHint(R.string.board_add_hint); - text.setImeOptions(EditorInfo.IME_FLAG_NO_FULLSCREEN); - - AlertDialog dialog = new AlertDialog.Builder(this) - .setPositiveButton(R.string.add, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface d, int which) { - String value = text.getText().toString(); - - if (!TextUtils.isEmpty(value)) { - addBoard(value.toLowerCase(Locale.ENGLISH)); - } - } - }).setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface d, int which) { - } - }).setTitle(R.string.board_add).setView(text).create(); - - AndroidUtils.requestKeyboardFocus(dialog, text); - - dialog.show(); - } - - private static class FillAdapter extends ArrayAdapter implements Filterable { - private List currentlyEditing; - private View autoCompleteView; - private final Filter filter; - private final List filtered = new ArrayList<>(); - - public FillAdapter(Context context, int resource) { - super(context, resource); - - filter = new Filter() { - @Override - protected synchronized FilterResults performFiltering(CharSequence constraint) { - FilterResults results = new FilterResults(); - - if (TextUtils.isEmpty(constraint) || (constraint.toString().startsWith(" "))) { - results.values = null; - results.count = 0; - } else { - List keys = getFiltered(constraint.toString()); - results.values = keys; - results.count = keys.size(); - } - - return results; - } - - @SuppressWarnings("unchecked") - @Override - protected void publishResults(CharSequence constraint, FilterResults results) { - filtered.clear(); - - if (ChanSettings.getBoardEditorFillerEnabled()) { - if (results.values != null) { - filtered.addAll((List) results.values); - } else { - filtered.addAll(getBoards()); - } - } - - notifyDataSetChanged(); - } - }; - } - - public void setEditingList(List list) { - currentlyEditing = list; - } - - public void setAutoCompleteView(View autoCompleteView) { - this.autoCompleteView = autoCompleteView; - } - - @Override - public int getCount() { - return filtered.size(); - } - - @Override - public String getItem(int position) { - return filtered.get(position).value; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); - - TextView view = (TextView) inflater.inflate(android.R.layout.simple_list_item_1, null); - Board b = filtered.get(position); - view.setText(b.value + " - " + b.key); - - view.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - InputMethodManager imm = (InputMethodManager) getContext().getSystemService( - Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(autoCompleteView.getWindowToken(), 0); - } - - return false; - } - }); - - return view; - } - - @Override - public Filter getFilter() { - return filter; - } - - private List getFiltered(String filter) { - String lowered = filter.toLowerCase(Locale.ENGLISH); - List list = new ArrayList<>(); - for (Board b : getBoards()) { - if ((b.key.toLowerCase(Locale.ENGLISH).contains(lowered) || b.value.toLowerCase(Locale.ENGLISH) - .contains(lowered))) { - list.add(b); - } - } - return list; - } - - private boolean haveBoard(String value) { - for (Board b : currentlyEditing) { - if (b.value.equals(value)) - return true; - } - return false; - } - - private List getBoards() { - // Lets be cheaty here: if the user has nsfw boards in the list, - // show them in the autofiller. - boolean showUnsafe = false; - for (Board has : currentlyEditing) { - if (!has.workSafe) { - showUnsafe = true; - break; - } - } - - List s = new ArrayList<>(); - for (Board b : ChanApplication.getBoardManager().getAllBoards()) { - if (!haveBoard(b.value) && (showUnsafe || b.workSafe)) - s.add(b); - } - return s; - } - } - - private class NiceDragSortController extends DragSortController { - private final ListView listView; - private final ArrayAdapter adapter; - - public NiceDragSortController(DragSortListView listView, ArrayAdapter adapter) { - super(listView, R.id.drag_handle, DragSortController.ON_DOWN, 0); - this.listView = listView; - this.adapter = adapter; - setSortEnabled(true); - setRemoveEnabled(false); - } - - @Override - public View onCreateFloatView(int position) { - return adapter.getView(position, null, listView); - } - - @Override - public void onDragFloatView(View floatView, Point floatPoint, Point touchPoint) { - } - - @Override - public void onDestroyFloatView(View floatView) { - } - } - - private class BoardEditAdapter extends ArrayAdapter { - public BoardEditAdapter(Context context, int textViewResourceId, List objects) { - super(context, textViewResourceId, objects); - } - - @Override - public boolean hasStableIds() { - return true; - } - - @Override - public long getItemId(int position) { - return getItem(position).hashCode(); - } - - @Override - public View getView(final int position, View convertView, ViewGroup parent) { - View inflated = LayoutInflater.from(getContext()).inflate(R.layout.board_edit_item, null); - TextView text = (TextView) inflated.findViewById(R.id.text); - Board b = getItem(position); - text.setText(b.value + " - " + b.key); - - return inflated; - } - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/activity/ChanActivity.java b/Clover/app/src/main/java/org/floens/chan/ui/activity/ChanActivity.java deleted file mode 100644 index 053b4f84..00000000 --- a/Clover/app/src/main/java/org/floens/chan/ui/activity/ChanActivity.java +++ /dev/null @@ -1,759 +0,0 @@ -/* - * Clover - 4chan browser https://github.com/Floens/Clover/ - * Copyright (C) 2014 Floens - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.floens.chan.ui.activity; - -import android.app.AlertDialog; -import android.app.FragmentTransaction; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.res.Configuration; -import android.net.Uri; -import android.os.Bundle; -import android.support.v7.app.ActionBar; -import android.support.v7.app.ActionBarDrawerToggle; -import android.util.DisplayMetrics; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewGroup.LayoutParams; -import android.widget.AdapterView; -import android.widget.BaseAdapter; -import android.widget.FrameLayout; -import android.widget.Spinner; -import android.widget.TextView; - -import org.floens.chan.ChanApplication; -import org.floens.chan.R; -import org.floens.chan.chan.ChanUrls; -import org.floens.chan.core.loader.ChanLoader; -import org.floens.chan.core.manager.ThreadManager; -import org.floens.chan.core.model.Board; -import org.floens.chan.core.model.ChanThread; -import org.floens.chan.core.model.Loadable; -import org.floens.chan.core.model.Pin; -import org.floens.chan.core.model.Post; -import org.floens.chan.core.settings.ChanSettings; -import org.floens.chan.ui.fragment.ThreadFragment; -import org.floens.chan.utils.Logger; - -import java.util.List; - -import static org.floens.chan.utils.AndroidUtils.dp; - -public class ChanActivity extends BaseActivity implements AdapterView.OnItemSelectedListener { - private static final String TAG = "ChanActivity"; - - private Loadable boardLoadable; - private Loadable threadLoadable; - private ThreadFragment boardFragment; - private ThreadFragment threadFragment; - - private boolean ignoreNextOnItemSelected = false; - private Spinner boardSpinner; - private BoardSpinnerAdapter spinnerAdapter; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - boardLoadable = new Loadable(); - threadLoadable = new Loadable(); - - boardFragment = ThreadFragment.newInstance(this); - setBoardFragmentViewMode(); - - threadFragment = ThreadFragment.newInstance(this); - - FragmentTransaction ft = getFragmentManager().beginTransaction(); - ft.replace(R.id.left_pane, boardFragment); - ft.replace(R.id.right_pane, threadFragment); - ft.commitAllowingStateLoss(); - - final ActionBar actionBar = getSupportActionBar(); - - boardSpinner = new Spinner(this); - spinnerAdapter = new BoardSpinnerAdapter(this, boardSpinner); - boardSpinner.setAdapter(spinnerAdapter); - boardSpinner.setOnItemSelectedListener(this); - - actionBar.setCustomView(boardSpinner); - actionBar.setDisplayShowCustomEnabled(true); - - updatePaneState(); - - Intent startIntent = getIntent(); - Uri startUri = startIntent.getData(); - - if (savedInstanceState != null) { - Loadable threadTmp = new Loadable(); - threadTmp.readFromBundle(this, "thread", savedInstanceState); - startLoadingThread(threadTmp); - - // Reset page etc. - Loadable tmp = new Loadable(); - tmp.readFromBundle(this, "board", savedInstanceState); - startLoadingBoard(new Loadable(tmp.board)); - } else { - if (startUri != null) { - handleIntentURI(startUri); - } - - if (boardLoadable.mode == Loadable.Mode.INVALID) { - List savedValues = ChanApplication.getBoardManager().getSavedBoards(); - if (savedValues.size() > 0) { - startLoadingBoard(new Loadable(savedValues.get(0).value)); - } - } - } - - if (startIntent.getExtras() != null) { - handleExtraBundle(startIntent.getExtras()); - } - - ignoreNextOnItemSelected = true; - } - - @Override - protected void onNewIntent(final Intent intent) { - super.onNewIntent(intent); - - if (intent.getExtras() != null) { - handleExtraBundle(intent.getExtras()); - } - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - - boardLoadable.writeToBundle(this, "board", outState); - threadLoadable.writeToBundle(this, "thread", outState); - } - - @Override - protected void onStart() { - super.onStart(); - - ChanApplication.getInstance().activityEnteredForeground(); - } - - @Override - protected void onStop() { - super.onStop(); - - ChanApplication.getInstance().activityEnteredBackground(); - } - - @Override - protected void onPause() { - super.onPause(); - - ChanApplication.getWatchManager().updateDatabase(); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - -// ChanApplication.getBoardManager().removeListener(this); - } - - @Override - protected void initDrawer() { - pinDrawerListener = new ActionBarDrawerToggle(this, pinDrawer, R.string.drawer_open, R.string.drawer_close); - - super.initDrawer(); - } - - @Override - protected void onPostCreate(Bundle savedInstanceState) { - super.onPostCreate(savedInstanceState); - pinDrawerListener.syncState(); - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - pinDrawerListener.onConfigurationChanged(newConfig); - - updatePaneState(); - } - - @Override - public void onBackPressed() { - if (pinDrawer.isDrawerOpen(pinDrawerView)) { - pinDrawer.closeDrawer(pinDrawerView); - } else { - if (threadPane.isOpen()) { - super.onBackPressed(); - } else { - threadPane.openPane(); - } - } - } - - @Override - public void openPin(Pin pin) { - startLoadingThread(pin.loadable); - - pinDrawer.closeDrawer(pinDrawerView); - } - - @Override - public void onOPClicked(Post post) { - Loadable l = new Loadable(post.board, post.no); - l.generateTitle(post); - startLoadingThread(l); - } - - @Override - public void onOpenThread(Loadable thread) { - startLoadingThread(thread); - } - - @Override - public void onThreadLoaded(ChanThread thread) { - updateActionBarState(); - pinnedAdapter.notifyDataSetChanged(); - } - - @Override - public void updatePin(Pin pin) { - super.updatePin(pin); - updateActionBarState(); - } - - @Override - public void removePin(Pin pin) { - super.removePin(pin); - updateActionBarState(); - } - - @Override - public void onNothingSelected(final AdapterView parent) { - } - - @Override - public void onPanelClosed(View view) { - updateActionBarState(); - } - - @Override - public void onPanelOpened(View view) { - updateActionBarState(); - } - -// @Override -// public void onBoardsChanged() { -// spinnerAdapter.setBoards(); -// spinnerAdapter.notifyDataSetChanged(); -// } - - private void handleExtraBundle(Bundle extras) { - int pinId = extras.getInt("pin_id", -2); - if (pinId != -2) { - if (pinId == -1) { - pinDrawer.openDrawer(pinDrawerView); - } else { - Pin pin = ChanApplication.getWatchManager().findPinById(pinId); - if (pin != null) { - startLoadingThread(pin.loadable); - } - } - } - } - - private void updatePaneState() { - DisplayMetrics metrics = new DisplayMetrics(); - getWindowManager().getDefaultDisplay().getMetrics(metrics); - int width = metrics.widthPixels; - - FrameLayout left = (FrameLayout) findViewById(R.id.left_pane); - FrameLayout right = (FrameLayout) findViewById(R.id.right_pane); - - LayoutParams leftParams = left.getLayoutParams(); - LayoutParams rightParams = right.getLayoutParams(); - - boolean wasSlidable = threadPane.isSlideable(); - boolean isSlidable; - - // Content view dp's: - // Nexus 4 is 384 x 640 dp - // Nexus 7 is 600 x 960 dp - // Nexus 10 is 800 x 1280 dp - - if (ChanSettings.getForcePhoneLayout()) { - leftParams.width = width - dp(30); - rightParams.width = width; - isSlidable = true; - } else { - if (width < dp(400)) { - leftParams.width = width - dp(30); - rightParams.width = width; - isSlidable = true; - } else if (width < dp(800)) { - leftParams.width = width - dp(60); - rightParams.width = width; - isSlidable = true; - } else if (width < dp(1000)) { - leftParams.width = dp(300); - rightParams.width = width - dp(300); - isSlidable = false; - } else { - leftParams.width = dp(400); - rightParams.width = width - dp(400); - isSlidable = false; - } - } - - left.setLayoutParams(leftParams); - right.setLayoutParams(rightParams); - - threadPane.requestLayout(); - left.requestLayout(); - right.requestLayout(); - - LayoutParams drawerParams = pinDrawerView.getLayoutParams(); - - if (width < dp(340)) { - drawerParams.width = dp(280); - } else { - drawerParams.width = dp(320); - } - - pinDrawerView.setLayoutParams(drawerParams); - - updateActionBarState(); - - if (isSlidable != wasSlidable) { - // Terrible hack to sync state for some devices when it changes slidable mode - threadPane.postDelayed(new Runnable() { - @Override - public void run() { - updateActionBarState(); - } - }, 1000); - } - } - - private void updateActionBarState() { - // Force the actionbar state after the ThreadPane layout, - // otherwise the ThreadPane incorrectly reports that it's not slidable. - threadPane.post(new Runnable() { - @Override - public void run() { - updateActionBarStateCallback(); - } - }); - } - - private void updateActionBarStateCallback() { - final ActionBar actionBar = getSupportActionBar(); - - if (threadPane.isSlideable()) { - if (threadPane.isOpen()) { - actionBar.setDisplayShowCustomEnabled(true); - spinnerAdapter.setBoard(boardLoadable.board); - actionBar.setTitle(""); - pinDrawerListener.setDrawerIndicatorEnabled(true); - - if (boardLoadable.isBoardMode()) { - setShareUrl(ChanUrls.getBoardUrlDesktop(boardLoadable.board)); - } else if (boardLoadable.isCatalogMode()) { - setShareUrl(ChanUrls.getCatalogUrlDesktop(boardLoadable.board)); - } - } else { - actionBar.setDisplayShowCustomEnabled(false); - actionBar.setTitle(threadLoadable.title); - pinDrawerListener.setDrawerIndicatorEnabled(false); - - if (threadLoadable.isThreadMode()) - setShareUrl(ChanUrls.getThreadUrlDesktop(threadLoadable.board, threadLoadable.no)); - } - } else { - actionBar.setDisplayShowCustomEnabled(true); - pinDrawerListener.setDrawerIndicatorEnabled(true); - actionBar.setTitle(threadLoadable.title); - - if (threadLoadable.isThreadMode()) { - setShareUrl(ChanUrls.getThreadUrlDesktop(threadLoadable.board, threadLoadable.no)); - } - } - - actionBar.setHomeButtonEnabled(true); - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setDisplayShowTitleEnabled(true); - - invalidateOptionsMenu(); - } - - @Override - public boolean onPrepareOptionsMenu(Menu menu) { - boolean open = threadPane.isOpen(); - boolean slidable = threadPane.isSlideable(); - - setMenuItemEnabled(menu.findItem(R.id.action_reload_board), slidable && open); - setMenuItemEnabled(menu.findItem(R.id.action_reload_thread), slidable && !open); - setMenuItemEnabled(menu.findItem(R.id.action_reload_tablet), !slidable); - - setMenuItemEnabled(menu.findItem(R.id.action_pin), !slidable || !open); - setMenuItemEnabled(menu.findItem(R.id.action_download_album), !slidable || !open); - - setMenuItemEnabled(menu.findItem(R.id.action_reply), slidable); - setMenuItemEnabled(menu.findItem(R.id.action_reply_tablet), !slidable); - - setMenuItemEnabled(menu.findItem(R.id.action_board_view_mode), !slidable || open); - - if (ChanSettings.getBoardViewMode().equals("list")) { - menu.findItem(R.id.action_board_view_mode_list).setChecked(true); - } else if (ChanSettings.getBoardViewMode().equals("grid")) { - menu.findItem(R.id.action_board_view_mode_grid).setChecked(true); - } - - setMenuItemEnabled(menu.findItem(R.id.action_search), slidable); - setMenuItemEnabled(menu.findItem(R.id.action_search_tablet), !slidable); - - boolean bookmarkedFilled = false; - if (threadLoadable.mode == Loadable.Mode.THREAD) { - Pin pin = ChanApplication.getWatchManager().findPinByLoadable(threadLoadable); - if (pin != null) { - bookmarkedFilled = true; - } - } - - menu.findItem(R.id.action_pin).setIcon(bookmarkedFilled ? R.drawable.ic_bookmark_filled : R.drawable.ic_bookmark); - - return super.onPrepareOptionsMenu(menu); - } - - private void setMenuItemEnabled(MenuItem item, boolean enabled) { - if (item != null) { - item.setVisible(enabled); - item.setEnabled(enabled); - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (pinDrawerListener.onOptionsItemSelected(item)) { - return true; - } - - switch (item.getItemId()) { - case R.id.action_reload_board: - case R.id.action_reload_tablet_board: - boardFragment.reload(); - return true; - case R.id.action_reload_thread: - case R.id.action_reload_tablet_thread: - threadFragment.reload(); - return true; - case R.id.action_reply: - if (threadPane.isOpen()) { - boardFragment.openReply(); - } else { - threadFragment.openReply(); - } - return true; - case R.id.action_reply_board: - boardFragment.openReply(); - - return true; - case R.id.action_reply_thread: - threadFragment.openReply(); - - return true; - case R.id.action_pin: - if (threadFragment.hasLoader()) { - ChanLoader chanLoader = threadFragment.getLoader(); - if (chanLoader != null && chanLoader.getLoadable().isThreadMode() && chanLoader.getThread() != null) { - Pin pin = ChanApplication.getWatchManager().findPinByLoadable(threadLoadable); - if (pin != null) { - ChanApplication.getWatchManager().removePin(pin); - } else { - ChanApplication.getWatchManager().addPin(chanLoader.getLoadable(), chanLoader.getThread().op); - } - updateActionBarState(); - } - } - - return true; - case R.id.action_open_browser: - openInBrowser(); - - return true; - case R.id.action_board_view_mode_grid: - if (!ChanSettings.getBoardViewMode().equals("grid")) { - ChanSettings.setBoardViewMode("grid"); - setBoardFragmentViewMode(); - startLoadingBoard(boardLoadable); - } - return true; - case R.id.action_board_view_mode_list: - if (!ChanSettings.getBoardViewMode().equals("list")) { - ChanSettings.setBoardViewMode("list"); - setBoardFragmentViewMode(); - startLoadingBoard(boardLoadable); - } - return true; - case R.id.action_search: - if (threadPane.isOpen()) { - boardFragment.startFiltering(); - } else { - threadFragment.startFiltering(); - } - return true; - case R.id.action_search_board: - boardFragment.startFiltering(); - return true; - case R.id.action_search_thread: - threadFragment.startFiltering(); - return true; - case android.R.id.home: - threadPane.openPane(); - - return true; - } - - return super.onOptionsItemSelected(item); - } - - @Override - public void onItemSelected(final AdapterView parent, final View view, final int position, final long id) { - if (ignoreNextOnItemSelected) { - Logger.d(TAG, "Ignoring onItemSelected"); - ignoreNextOnItemSelected = false; - return; - } - - spinnerAdapter.onItemSelected(position); - } - - private void startLoadingBoard(Loadable loadable) { - if (loadable.mode == Loadable.Mode.INVALID) - return; - - boardLoadable = loadable; - - if (ChanSettings.getBoardMode().equals("catalog")) { - boardLoadable.mode = Loadable.Mode.CATALOG; - } else if (ChanSettings.getBoardMode().equals("pages")) { - boardLoadable.mode = Loadable.Mode.BOARD; - } - - // Force catalog mode when using grid - if (boardFragment.getViewMode() == ThreadManager.ViewMode.GRID) { - boardLoadable.mode = Loadable.Mode.CATALOG; - } - - boardFragment.bindLoadable(boardLoadable); - boardFragment.requestData(); - - updateActionBarState(); - } - - private void startLoadingThread(Loadable loadable) { - if (loadable.mode == Loadable.Mode.INVALID) - return; - - Pin pin = ChanApplication.getWatchManager().findPinByLoadable(loadable); - if (pin != null) { - // Use the loadable from the pin. - // This way we can store the listview position in the pin loadable, - // and not in a separate loadable instance. - loadable = pin.loadable; - } - - if (threadLoadable.equals(loadable)) { - threadFragment.requestNextData(); - } else { - threadLoadable = loadable; - threadFragment.bindLoadable(loadable); - threadFragment.requestData(); - } - - threadPane.closePane(); - - updateActionBarState(); - } - - /** - * Handle opening from an external url. - * - * @param startUri - */ - private void handleIntentURI(Uri startUri) { - Logger.d(TAG, "Opening " + startUri.getPath()); - - List parts = startUri.getPathSegments(); - - if (parts.size() == 1) { - // Board mode - String rawBoard = parts.get(0); - if (ChanApplication.getBoardManager().getBoardExists(rawBoard)) { - startLoadingBoard(new Loadable(rawBoard)); - } else { - handleIntentURIFallback(startUri.toString()); - } - } else if (parts.size() >= 3) { - // Thread mode - String rawBoard = parts.get(0); - int no = -1; - - try { - no = Integer.parseInt(parts.get(2)); - } catch (NumberFormatException e) { - } - - int post = -1; - String fragment = startUri.getFragment(); - if (fragment != null) { - int index = fragment.indexOf("p"); - if (index >= 0) { - try { - post = Integer.parseInt(fragment.substring(index + 1)); - } catch (NumberFormatException e) { - } - } - } - - if (no >= 0 && ChanApplication.getBoardManager().getBoardExists(rawBoard)) { - startLoadingThread(new Loadable(rawBoard, no)); - if (post >= 0) { - threadFragment.highlightPost(post); - } - } else { - handleIntentURIFallback(startUri.toString()); - } - } else { - showUrlOpenPicker(startUri.toString()); - } - } - - private void handleIntentURIFallback(final String url) { - new AlertDialog.Builder(this).setTitle(R.string.open_unknown_title).setMessage(R.string.open_unknown) - .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - finish(); - } - }).setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - showUrlOpenPicker(url); - } - }).setCancelable(false).create().show(); - } - - private void setBoardFragmentViewMode() { - if (ChanSettings.getBoardViewMode().equals("list")) { - boardFragment.setViewMode(ThreadManager.ViewMode.LIST); - } else if (ChanSettings.getBoardViewMode().equals("grid")) { - boardFragment.setViewMode(ThreadManager.ViewMode.GRID); - } - } - - private class BoardSpinnerAdapter extends BaseAdapter { - private Context context; - private Spinner spinner; - private List boards; - private int lastSelectedPosition = 0; - - public BoardSpinnerAdapter(Context context, Spinner spinner) { - this.context = context; - this.spinner = spinner; - setBoards(); - } - - public void setBoards() { - boards = ChanApplication.getBoardManager().getSavedBoards(); - } - - public void setBoard(String boardValue) { - for (int i = 0; i < boards.size(); i++) { - if (boards.get(i).value.equals(boardValue)) { - spinner.setSelection(i); - return; - } - } - } - - public void onItemSelected(int position) { - if (position >= 0 && position < boards.size()) { - Loadable board = new Loadable(boards.get(position).value); - - // onItemSelected is called after the view initializes, - // ignore if it's the same board - if (boardLoadable.equals(board)) - return; - - startLoadingBoard(board); - - lastSelectedPosition = position; - } else { - startActivity(new Intent(context, BoardEditor.class)); - spinner.setSelection(lastSelectedPosition); - } - } - - @Override - public int getCount() { - return boards.size() + 1; - } - - @Override - public long getItemId(final int position) { - return position; - } - - @Override - public String getItem(final int position) { - if (position == getCount() - 1) { - return context.getString(R.string.board_select_add); - } else { - return boards.get(position).key; - } - } - - @Override - public View getDropDownView(int position, View convertView, ViewGroup parent) { - return createView(position, convertView, parent, true); - } - - @Override - public View getView(final int position, View convertView, final ViewGroup parent) { - return createView(position, convertView, parent, false); - } - - private View createView(int position, View convertView, ViewGroup parent, boolean dropDown) { - if (position == getCount() - 1) { - TextView textView = (TextView) LayoutInflater.from(context).inflate(R.layout.board_select_add, parent, false); - textView.setText(getItem(position)); - return textView; - } else { - TextView textView = (TextView) LayoutInflater.from(context).inflate( - dropDown ? R.layout.board_select_spinner_dropdown : R.layout.board_select_spinner, parent, false); - textView.setText(getItem(position)); - return textView; - } - } - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/activity/DeveloperActivity.java b/Clover/app/src/main/java/org/floens/chan/ui/activity/DeveloperActivity.java deleted file mode 100644 index 39d6c15d..00000000 --- a/Clover/app/src/main/java/org/floens/chan/ui/activity/DeveloperActivity.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Clover - 4chan browser https://github.com/Floens/Clover/ - * Copyright (C) 2014 Floens - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.floens.chan.ui.activity; - -import android.os.Bundle; -import android.view.View; -import android.widget.Button; -import android.widget.LinearLayout; -import android.widget.TextView; - -import org.floens.chan.ChanApplication; -import org.floens.chan.R; -import org.floens.chan.core.model.SavedReply; -import org.floens.chan.ui.ThemeActivity; - -import java.util.Random; - -public class DeveloperActivity extends ThemeActivity { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setTheme(); - setContentView(R.layout.toolbar_activity); - setToolbar(); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - - LinearLayout wrapper = new LinearLayout(this); - wrapper.setOrientation(LinearLayout.VERTICAL); - - Button crashButton = new Button(this); - - crashButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - @SuppressWarnings({"unused", "NumericOverflow"}) - int i = 1 / 0; - } - }); - crashButton.setText("Crash the app"); - - wrapper.addView(crashButton); - - String dbSummary = ""; - - dbSummary += "Database summary:\n"; - dbSummary += ChanApplication.getDatabaseManager().getSummary(); - - TextView db = new TextView(this); - db.setPadding(0, 25, 0, 0); - db.setText(dbSummary); - wrapper.addView(db); - - Button resetDbButton = new Button(this); - resetDbButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - ChanApplication.getDatabaseManager().reset(); - System.exit(0); - } - }); - resetDbButton.setText("Delete database"); - wrapper.addView(resetDbButton); - - Button savedReplyDummyAdd = new Button(this); - savedReplyDummyAdd.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(final View v) { - Random r = new Random(); - int j = 0; - for (int i = 0; i < 100; i++) { - j += r.nextInt(10000); - ChanApplication.getDatabaseManager().saveReply(new SavedReply("g", j, "pass")); - } - recreate(); - } - }); - savedReplyDummyAdd.setText("Add test rows to savedReply"); - wrapper.addView(savedReplyDummyAdd); - - Button trimSavedReply = new Button(this); - trimSavedReply.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(final View v) { - ChanApplication.getDatabaseManager().trimSavedRepliesTable(10); - recreate(); - } - }); - trimSavedReply.setText("Trim savedreply table"); - wrapper.addView(trimSavedReply); - - setContentView(wrapper); - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/activity/ImagePickActivity.java b/Clover/app/src/main/java/org/floens/chan/ui/activity/ImagePickActivity.java index e99e01f5..055eaf1a 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/activity/ImagePickActivity.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/activity/ImagePickActivity.java @@ -25,7 +25,7 @@ import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.provider.OpenableColumns; -import org.floens.chan.ChanApplication; +import org.floens.chan.Chan; import org.floens.chan.core.reply.ReplyManager; import org.floens.chan.utils.IOUtils; import org.floens.chan.utils.Logger; @@ -53,7 +53,7 @@ public class ImagePickActivity extends Activity implements Runnable { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - replyManager = ChanApplication.getReplyManager(); + replyManager = Chan.getReplyManager(); Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.addCategory(Intent.CATEGORY_OPENABLE); diff --git a/Clover/app/src/main/java/org/floens/chan/ui/activity/ImageViewActivity.java b/Clover/app/src/main/java/org/floens/chan/ui/activity/ImageViewActivity.java deleted file mode 100644 index c8d9202c..00000000 --- a/Clover/app/src/main/java/org/floens/chan/ui/activity/ImageViewActivity.java +++ /dev/null @@ -1,271 +0,0 @@ -/* - * Clover - 4chan browser https://github.com/Floens/Clover/ - * Copyright (C) 2014 Floens - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.floens.chan.ui.activity; - -import android.app.Activity; -import android.content.Intent; -import android.os.Bundle; -import android.support.v4.view.ViewPager; -import android.view.Menu; -import android.view.MenuItem; -import android.view.SubMenu; -import android.view.View; -import android.widget.ProgressBar; - -import org.floens.chan.R; -import org.floens.chan.chan.ImageSearch; -import org.floens.chan.core.settings.ChanSettings; -import org.floens.chan.core.manager.ThreadManager; -import org.floens.chan.core.model.Post; -import org.floens.chan.ui.ThemeActivity; -import org.floens.chan.ui.adapter.ImageViewAdapter; -import org.floens.chan.ui.adapter.PostAdapter; -import org.floens.chan.ui.fragment.ImageViewFragment; -import org.floens.chan.utils.ImageSaver; -import org.floens.chan.utils.Logger; - -import java.util.ArrayList; -import java.util.List; - -/** - * An fragment pager that contains images. Call setPosts first, and then start - * the activity with startActivity() - */ -public class ImageViewActivity extends ThemeActivity implements ViewPager.OnPageChangeListener { - private static final String TAG = "ImageViewActivity"; - - private static PostAdapter postAdapterStatic; - private static int selectedNoStatic = -1; - private static ThreadManager threadManagerStatic; - - private PostAdapter postAdapter; - private ThreadManager threadManager; - private int selectedNo; - - private ImageViewAdapter adapter; - private ViewPager viewPager; - private ProgressBar progressBar; - private int currentPosition; - - /** - * Set the posts to show - * - * @param adapter the adapter to get image data from - * @param selected the no that the user clicked on - */ - public static void launch(Activity activity, PostAdapter adapter, int selected, ThreadManager threadManager) { - postAdapterStatic = adapter; - selectedNoStatic = selected; - threadManagerStatic = threadManager; - - Intent intent = new Intent(activity, ImageViewActivity.class); - activity.startActivity(intent); - activity.overridePendingTransition(R.anim.fade_in, R.anim.fade_out); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - if (postAdapterStatic == null || threadManagerStatic == null) { - Logger.e(TAG, "postadapter or threadmanager null"); - finish(); - return; - } - - super.onCreate(savedInstanceState); - - threadManager = threadManagerStatic; - threadManagerStatic = null; - postAdapter = postAdapterStatic; - postAdapterStatic = null; - selectedNo = selectedNoStatic; - selectedNoStatic = -1; - - setContentView(R.layout.image_view); - setToolbar(); - - initProgressBar(); - initPager(); - } - - private void initProgressBar() { - progressBar = (ProgressBar) findViewById(R.id.progress_bar); -// progressBar.setProgressDrawable(getResources().getDrawable(R.drawable.progressbar_no_bg)); - progressBar.setIndeterminate(false); - progressBar.setMax(1000000); - } - - private void initPager() { - // Get the posts with images - ArrayList imagePosts = new ArrayList<>(); -// for (Post post : postAdapter.getList()) { -// if (post.hasImage) { -// imagePosts.add(post); -// } -// } - - // Setup our pages and adapter - viewPager = (ViewPager) findViewById(R.id.image_pager); - adapter = new ImageViewAdapter(getFragmentManager(), this); - adapter.setList(imagePosts); - viewPager.setAdapter(adapter); - viewPager.setOnPageChangeListener(this); - - // Select the right image - for (int i = 0; i < imagePosts.size(); i++) { - if (imagePosts.get(i).no == selectedNo) { - viewPager.setCurrentItem(i); - onPageSelected(i); - break; - } - } - } - - @Override - protected void onStop() { - super.onStop(); - - // Avoid things like out of sync, since this is an activity. - finish(); - } - - @Override - public void finish() { - super.finish(); - overridePendingTransition(R.anim.fade_in, R.anim.fade_out); - } - - @Override - public void onPageScrollStateChanged(int state) { - } - - @Override - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { - } - - @Override - public void onPageSelected(int position) { - currentPosition = position; - - for (int i = -1; i <= 1; i++) { - ImageViewFragment fragment = getFragment(position + i); - if (fragment != null) { - fragment.onDeselected(); - } - } - - ImageViewFragment fragment = getFragment(currentPosition); - if (fragment != null) { - fragment.onSelected(adapter, position); - } - - Post post = adapter.getPost(position); - if (!threadManager.arePostRepliesOpen()) { -// postAdapter.scrollToPost(post.no); //TODO - } - } - - public void invalidateActionBar() { - invalidateOptionsMenu(); - } - - public void updateActionBarIfSelected(ImageViewFragment targetFragment) { - ImageViewFragment fragment = getFragment(currentPosition); - if (fragment != null && fragment == targetFragment) { - fragment.onSelected(adapter, currentPosition); - } - } - - public void setProgressBar(long current, long total, boolean done) { - if (done) { - progressBar.setVisibility(View.GONE); - } else { - progressBar.setVisibility(View.VISIBLE); - progressBar.setProgress((int) (((double) current / total) * progressBar.getMax())); - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - finish(); - return true; - case R.id.action_download_album: - if (adapter.getList().size() > 0) { - List list = new ArrayList<>(); - - String folderName = Post.generateTitle(adapter.getList().get(0), 10); - - String filename; - for (Post post : adapter.getList()) { - filename = (ChanSettings.getImageSaveOriginalFilename() ? post.tim : post.filename) + "." + post.ext; - list.add(new ImageSaver.DownloadPair(post.imageUrl, filename)); - } - - ImageSaver.getInstance().saveAll(this, folderName, list); - } - - return true; - default: - ImageViewFragment fragment = getFragment(currentPosition); - if (fragment != null) { - fragment.customOnOptionsItemSelected(item); - } - - return super.onOptionsItemSelected(item); - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.image_view, menu); - - MenuItem imageSearch = menu.findItem(R.id.action_image_search); - SubMenu subMenu = imageSearch.getSubMenu(); - for (ImageSearch engine : ImageSearch.engines) { - subMenu.add(Menu.NONE, engine.getId(), Menu.NONE, engine.getName()); - } - - return true; - } - - @Override - public boolean onPrepareOptionsMenu(Menu menu) { - ImageViewFragment fragment = getFragment(currentPosition); - if (fragment != null) { - fragment.onPrepareOptionsMenu(menu); - } - - return super.onPrepareOptionsMenu(menu); - } - - private ImageViewFragment getFragment(int i) { - if (adapter == null) { - return null; - } else if (i >= 0 && i < adapter.getCount()) { - Object o = adapter.instantiateItem(viewPager, i); - if (o instanceof ImageViewFragment) { - return (ImageViewFragment) o; - } else { - return null; - } - } else { - return null; - } - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/activity/LicenseActivity.java b/Clover/app/src/main/java/org/floens/chan/ui/activity/LicenseActivity.java deleted file mode 100644 index f427a29f..00000000 --- a/Clover/app/src/main/java/org/floens/chan/ui/activity/LicenseActivity.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Clover - 4chan browser https://github.com/Floens/Clover/ - * Copyright (C) 2014 Floens - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.floens.chan.ui.activity; - -import android.app.Activity; -import android.os.Bundle; -import android.webkit.WebView; - -import org.floens.chan.utils.ThemeHelper; - -public class LicenseActivity extends Activity { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - ThemeHelper.setTheme(this); - - WebView webView = new WebView(this); - webView.loadUrl("file:///android_asset/html/license.html"); - - setContentView(webView); - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/activity/PassSettingsActivity.java b/Clover/app/src/main/java/org/floens/chan/ui/activity/PassSettingsActivity.java deleted file mode 100644 index a1770d0b..00000000 --- a/Clover/app/src/main/java/org/floens/chan/ui/activity/PassSettingsActivity.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Clover - 4chan browser https://github.com/Floens/Clover/ - * Copyright (C) 2014 Floens - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.floens.chan.ui.activity; - -import android.app.AlertDialog; -import android.app.Fragment; -import android.app.FragmentTransaction; -import android.app.ProgressDialog; -import android.os.Bundle; -import android.preference.Preference; -import android.preference.PreferenceFragment; -import android.support.v7.widget.SwitchCompat; -import android.text.TextUtils; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.webkit.WebSettings; -import android.webkit.WebView; -import android.widget.CompoundButton; -import android.widget.CompoundButton.OnCheckedChangeListener; -import android.widget.TextView; - -import org.floens.chan.ChanApplication; -import org.floens.chan.R; -import org.floens.chan.core.reply.ReplyManager; -import org.floens.chan.core.reply.ReplyManager.PassResponse; -import org.floens.chan.core.settings.ChanSettings; -import org.floens.chan.ui.ThemeActivity; -import org.floens.chan.utils.AndroidUtils; - -public class PassSettingsActivity extends ThemeActivity implements OnCheckedChangeListener { - private SwitchCompat onSwitch; - private TextView toggleStatus; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setTheme(); - setContentView(R.layout.header_switch_layout); - setToolbar(); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - - findViewById(R.id.toggle_bar).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - onSwitch.toggle(); - } - }); - - toggleStatus = (TextView) findViewById(R.id.toggle_status); - onSwitch = (SwitchCompat) findViewById(R.id.toggle); - onSwitch.setOnCheckedChangeListener(this); - setSwitch(ChanSettings.getPassEnabled()); - - setFragment(ChanSettings.getPassEnabled()); - } - - @Override - public void onPause() { - super.onPause(); - - if (TextUtils.isEmpty(ChanSettings.getPassId())) { - ChanSettings.setPassEnabled(false); - setSwitch(false); - } - } - - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - setFragment(isChecked); - setSwitch(isChecked); - } - - private void setSwitch(boolean enabled) { - onSwitch.setChecked(enabled); - toggleStatus.setText(enabled ? R.string.on : R.string.off); - - ChanSettings.setPassEnabled(enabled); - } - - private void setFragment(boolean enabled) { - if (enabled) { - FragmentTransaction t = getFragmentManager().beginTransaction(); - t.replace(R.id.content, new PassSettingsFragment()); - t.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); - t.commit(); - } else { - FragmentTransaction t = getFragmentManager().beginTransaction(); - t.replace(R.id.content, new TextFragment()); - t.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); - t.commit(); - } - } - - public static class TextFragment extends Fragment { - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup group, Bundle savedInstanceState) { - View container = inflater.inflate(R.layout.preference_pass, null); - - TextView link = (TextView) container.findViewById(R.id.pass_link); - link.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - AndroidUtils.openLink(v.getContext().getString(R.string.pass_info_link)); - } - }); - - return container; - } - } - - public static class PassSettingsFragment extends PreferenceFragment { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - addPreferencesFromResource(R.xml.preference_pass); - - Preference login = findPreference("preference_pass_login"); - login.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - onLoginClick(ChanSettings.getPassToken(), ChanSettings.getPassPin()); - return true; - } - }); - - updateLoginButton(); - } - - private void updateLoginButton() { - findPreference("preference_pass_login").setTitle(TextUtils.isEmpty(ChanSettings.getPassId()) ? R.string.pass_login : R.string.pass_logout); - } - - private void onLoginClick(String token, String pin) { - if (TextUtils.isEmpty(ChanSettings.getPassId())) { - // Login - final ProgressDialog dialog = ProgressDialog.show(getActivity(), null, "Logging in"); - - ChanApplication.getReplyManager().postPass(token, pin, new ReplyManager.PassListener() { - @Override - public void onResponse(PassResponse response) { - dialog.dismiss(); - - if (getActivity() == null) - return; - - if (response.unknownError) { - WebView webView = new WebView(getActivity()); - WebSettings settings = webView.getSettings(); - settings.setSupportZoom(true); - - webView.loadData(response.responseData, "text/html", null); - - new AlertDialog.Builder(getActivity()).setView(webView).setNeutralButton(R.string.ok, null).show(); - } else { - new AlertDialog.Builder(getActivity()).setMessage(response.message) - .setNeutralButton(R.string.ok, null).show(); - ChanSettings.setPassId(response.passId); - } - - updateLoginButton(); - } - }); - } else { - // Logout - ChanSettings.setPassId(""); - updateLoginButton(); - } - } - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/activity/ReplyActivity.java b/Clover/app/src/main/java/org/floens/chan/ui/activity/ReplyActivity.java deleted file mode 100644 index 04d43ecf..00000000 --- a/Clover/app/src/main/java/org/floens/chan/ui/activity/ReplyActivity.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Clover - 4chan browser https://github.com/Floens/Clover/ - * Copyright (C) 2014 Floens - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.floens.chan.ui.activity; - -import android.app.Fragment; -import android.app.FragmentTransaction; -import android.os.Bundle; -import android.view.MenuItem; - -import org.floens.chan.R; -import org.floens.chan.core.model.Loadable; -import org.floens.chan.ui.ThemeActivity; -import org.floens.chan.ui.fragment.ReplyFragment; -import org.floens.chan.utils.Logger; - -public class ReplyActivity extends ThemeActivity { - private static final String TAG = "ReplyActivity"; - - private static Loadable staticLoadable; - - public static void setLoadable(Loadable l) { - staticLoadable = l; - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - Loadable loadable = staticLoadable; - staticLoadable = null; - - if (loadable != null && savedInstanceState == null) { - setTheme(); - setContentView(R.layout.toolbar_activity); - setToolbar(); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - - FragmentTransaction ft = getFragmentManager().beginTransaction(); - ft.replace(R.id.content, ReplyFragment.newInstance(loadable, false), "reply"); - ft.commitAllowingStateLoss(); - } else if (savedInstanceState == null) { - Logger.e(TAG, "Loadable was null, exiting!"); - finish(); - } - } - - @Override - public void onBackPressed() { - Fragment f = getFragmentManager().findFragmentByTag("reply"); - if (f != null && ((ReplyFragment) f).onBackPressed()) { - super.onBackPressed(); - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - finish(); - - return true; - } - - return super.onOptionsItemSelected(item); - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/activity/SettingsActivity.java b/Clover/app/src/main/java/org/floens/chan/ui/activity/SettingsActivity.java deleted file mode 100644 index 8dd80be0..00000000 --- a/Clover/app/src/main/java/org/floens/chan/ui/activity/SettingsActivity.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Clover - 4chan browser https://github.com/Floens/Clover/ - * Copyright (C) 2014 Floens - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.floens.chan.ui.activity; - -import android.content.Intent; -import android.os.Bundle; -import android.view.Menu; -import android.view.MenuItem; - -import org.floens.chan.R; -import org.floens.chan.ui.ThemeActivity; -import org.floens.chan.ui.fragment.SettingsFragment; -import org.floens.chan.utils.ThemeHelper; - -public class SettingsActivity extends ThemeActivity { - private static boolean doingThemeRestart = false; - private static ThemeHelper.Theme lastTheme; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setTheme(); - setContentView(R.layout.toolbar_activity); - setToolbar(); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - - if (!doingThemeRestart) { - lastTheme = ThemeHelper.getInstance().getTheme(); - } - - SettingsFragment frag = new SettingsFragment(); - frag.setArguments(getIntent().getExtras()); - getFragmentManager().beginTransaction().replace(R.id.content, frag).commit(); - } - - public void restart(Intent intent) { - doingThemeRestart = true; - startActivity(intent); - finish(); - doingThemeRestart = false; - overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out); - } - - @Override - protected void onPause() { - super.onPause(); - - if (ThemeHelper.getInstance().getTheme() != lastTheme) { - lastTheme = ThemeHelper.getInstance().getTheme(); - - BaseActivity.doRestartOnResume = true; - } - } - - @Override - public boolean onCreateOptionsMenu(final Menu menu) { - getMenuInflater().inflate(R.menu.settings, menu); - - return true; - } - - @Override - public boolean onOptionsItemSelected(final MenuItem item) { - if (item.getItemId() == R.id.action_settings_advanced) { - startActivity(new Intent(this, AdvancedSettingsActivity.class)); - return true; - } else if (item.getItemId() == android.R.id.home) { - finish(); - return true; - } else { - return super.onOptionsItemSelected(item); - } - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/activity/StartActivity.java b/Clover/app/src/main/java/org/floens/chan/ui/activity/StartActivity.java index a2013473..41789331 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/activity/StartActivity.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/activity/StartActivity.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.activity; import android.app.AlertDialog; @@ -7,7 +24,7 @@ import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.ViewGroup; -import org.floens.chan.ChanApplication; +import org.floens.chan.Chan; import org.floens.chan.R; import org.floens.chan.controller.Controller; import org.floens.chan.core.settings.ChanSettings; @@ -103,21 +120,21 @@ public class StartActivity extends AppCompatActivity { protected void onStart() { super.onStart(); - ChanApplication.getInstance().activityEnteredForeground(); + Chan.getInstance().activityEnteredForeground(); } @Override protected void onStop() { super.onStop(); - ChanApplication.getInstance().activityEnteredBackground(); + Chan.getInstance().activityEnteredBackground(); } @Override protected void onPause() { super.onPause(); - ChanApplication.getWatchManager().updateDatabase(); + Chan.getWatchManager().updateDatabase(); } private Controller stackTop() { diff --git a/Clover/app/src/main/java/org/floens/chan/ui/activity/WatchSettingsActivity.java b/Clover/app/src/main/java/org/floens/chan/ui/activity/WatchSettingsActivity.java deleted file mode 100644 index 591e889b..00000000 --- a/Clover/app/src/main/java/org/floens/chan/ui/activity/WatchSettingsActivity.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Clover - 4chan browser https://github.com/Floens/Clover/ - * Copyright (C) 2014 Floens - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.floens.chan.ui.activity; - -import android.app.Fragment; -import android.app.FragmentTransaction; -import android.os.Bundle; -import android.preference.ListPreference; -import android.preference.Preference; -import android.preference.Preference.OnPreferenceChangeListener; -import android.preference.PreferenceFragment; -import android.support.v7.widget.SwitchCompat; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.CompoundButton; -import android.widget.CompoundButton.OnCheckedChangeListener; -import android.widget.TextView; - -import org.floens.chan.ChanApplication; -import org.floens.chan.R; -import org.floens.chan.core.settings.ChanSettings; -import org.floens.chan.ui.ThemeActivity; - -public class WatchSettingsActivity extends ThemeActivity implements OnCheckedChangeListener { - private SwitchCompat watchSwitch; - private TextView toggleStatus; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setTheme(); - setContentView(R.layout.header_switch_layout); - setToolbar(); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - - findViewById(R.id.toggle_bar).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - watchSwitch.toggle(); - } - }); - - toggleStatus = (TextView) findViewById(R.id.toggle_status); - watchSwitch = (SwitchCompat) findViewById(R.id.toggle); - watchSwitch.setOnCheckedChangeListener(this); - setSwitch(ChanSettings.getWatchEnabled()); - - setFragment(ChanSettings.getWatchEnabled()); - } - - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - setFragment(isChecked); - setSwitch(isChecked); - } - - private void setSwitch(boolean enabled) { - watchSwitch.setChecked(enabled); - toggleStatus.setText(enabled ? R.string.on : R.string.off); - - ChanSettings.setWatchEnabled(enabled); - } - - private void setFragment(boolean enabled) { - FragmentTransaction t = getFragmentManager().beginTransaction(); - if (enabled) { - t.replace(R.id.content, new WatchSettingsFragment()); - } else { - t.replace(R.id.content, TextFragment.newInstance(R.string.watch_info_text)); - } - t.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); - t.commit(); - } - - public static class TextFragment extends Fragment { - public static TextFragment newInstance(int textResource) { - TextFragment f = new TextFragment(); - Bundle bundle = new Bundle(); - bundle.putInt("text_resource", textResource); - f.setArguments(bundle); - return f; - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup group, Bundle savedInstanceState) { - ViewGroup container = (ViewGroup) inflater.inflate(R.layout.watch_description, null); - - TextView text = (TextView) container.findViewById(R.id.text); - text.setText(getArguments().getInt("text_resource")); - - return container; - } - } - - public static class WatchSettingsFragment extends PreferenceFragment { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - addPreferencesFromResource(R.xml.preference_watch); - - final ListPreference backgroundTimeout = (ListPreference) findPreference("preference_watch_background_timeout"); - String currentValue = backgroundTimeout.getValue(); - if (currentValue == null) { - backgroundTimeout.setValue((String) backgroundTimeout.getEntryValues()[0]); - currentValue = backgroundTimeout.getValue(); - } - updateListSummary(backgroundTimeout, currentValue); - - backgroundTimeout.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - updateListSummary(backgroundTimeout, newValue.toString()); - return true; - } - }); - - final ListPreference notifyMode = (ListPreference) findPreference("preference_watch_notify_mode"); - String currentNotifyMode = notifyMode.getValue(); - if (currentNotifyMode == null) { - notifyMode.setValue((String) notifyMode.getEntryValues()[0]); - currentNotifyMode = notifyMode.getValue(); - } - updateListSummary(notifyMode, currentNotifyMode); - - notifyMode.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - updateListSummary(notifyMode, newValue.toString()); - return true; - } - }); - - final ListPreference sound = (ListPreference) findPreference("preference_watch_sound"); - String currentSound = sound.getValue(); - if (currentSound == null) { - sound.setValue((String) sound.getEntryValues()[0]); - currentSound = sound.getValue(); - } - updateListSummary(sound, currentSound); - - sound.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - updateListSummary(sound, newValue.toString()); - return true; - } - }); - - final ListPreference led = (ListPreference) findPreference("preference_watch_led"); - String currentLed = led.getValue(); - if (currentLed == null) { - led.setValue((String) led.getEntryValues()[0]); - currentLed = led.getValue(); - } - updateListSummary(led, currentLed); - - led.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - updateListSummary(led, newValue.toString()); - return true; - } - }); - - findPreference("preference_watch_background_enabled").setOnPreferenceChangeListener(new OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(final Preference preference, final Object newValue) { - ChanApplication.getWatchManager().onBackgroundWatchingChanged((Boolean) newValue); - - return true; - } - }); - } - - private void updateListSummary(ListPreference backgroundTimeout, String value) { - int index = backgroundTimeout.findIndexOfValue(value); - backgroundTimeout.setSummary(backgroundTimeout.getEntries()[index]); - } - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/adapter/ImageViewAdapter.java b/Clover/app/src/main/java/org/floens/chan/ui/adapter/ImageViewAdapter.java deleted file mode 100644 index 09f90d44..00000000 --- a/Clover/app/src/main/java/org/floens/chan/ui/adapter/ImageViewAdapter.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Clover - 4chan browser https://github.com/Floens/Clover/ - * Copyright (C) 2014 Floens - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.floens.chan.ui.adapter; - -import android.app.Fragment; -import android.app.FragmentManager; -import android.support.v13.app.FragmentStatePagerAdapter; - -import org.floens.chan.core.model.Post; -import org.floens.chan.ui.activity.ImageViewActivity; -import org.floens.chan.ui.fragment.ImageViewFragment; - -import java.util.ArrayList; -import java.util.List; - -public class ImageViewAdapter extends FragmentStatePagerAdapter { - private final ImageViewActivity activity; - private final ArrayList postList = new ArrayList<>(); - - public ImageViewAdapter(FragmentManager fragmentManager, ImageViewActivity activity) { - super(fragmentManager); - this.activity = activity; - } - - @Override - public int getCount() { - return postList.size(); - } - - @Override - public Fragment getItem(int position) { - return ImageViewFragment.newInstance(postList.get(position), activity, position); - } - - public Post getPost(int position) { - if (position < 0 || position >= getCount()) - return null; - - return postList.get(position); - } - - public void setList(ArrayList list) { - postList.clear(); - postList.addAll(list); - - notifyDataSetChanged(); - } - - public List getList() { - return postList; - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/adapter/ImageViewerAdapter.java b/Clover/app/src/main/java/org/floens/chan/ui/adapter/ImageViewerAdapter.java index 66e314bc..5fb6f653 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/adapter/ImageViewerAdapter.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/adapter/ImageViewerAdapter.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.adapter; import android.content.Context; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/adapter/PinAdapter.java b/Clover/app/src/main/java/org/floens/chan/ui/adapter/PinAdapter.java index ab20dde1..9c4e56e0 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/adapter/PinAdapter.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/adapter/PinAdapter.java @@ -1,6 +1,22 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.adapter; -import android.os.Build; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; @@ -8,7 +24,7 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; -import org.floens.chan.ChanApplication; +import org.floens.chan.Chan; import org.floens.chan.R; import org.floens.chan.core.model.Pin; import org.floens.chan.core.settings.ChanSettings; @@ -21,7 +37,7 @@ import java.util.List; import static org.floens.chan.utils.AndroidUtils.ROBOTO_MEDIUM; import static org.floens.chan.utils.AndroidUtils.dp; -import static org.floens.chan.utils.AndroidUtils.getAttrDrawable; +import static org.floens.chan.utils.AndroidUtils.setRoundItemBackground; public class PinAdapter extends RecyclerView.Adapter implements SwipeListener.Callback { private static final int PIN_OFFSET = 3; @@ -156,7 +172,7 @@ public class PinAdapter extends RecyclerView.Adapter im @Override public void removeItem(int position) { - ChanApplication.getWatchManager().removePin(pins.get(position - PIN_OFFSET)); + Chan.getWatchManager().removePin(pins.get(position - PIN_OFFSET)); } @Override @@ -240,11 +256,7 @@ public class PinAdapter extends RecyclerView.Adapter im watchCountText = (TextView) itemView.findViewById(R.id.watch_count); watchCountText.setTypeface(ROBOTO_MEDIUM); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - watchCountText.setBackground(getAttrDrawable(itemView.getContext(), android.R.attr.selectableItemBackgroundBorderless)); - } else { - watchCountText.setBackgroundResource(R.drawable.item_background); - } + setRoundItemBackground(watchCountText); itemView.setOnClickListener(new View.OnClickListener() { @Override @@ -271,11 +283,7 @@ public class PinAdapter extends RecyclerView.Adapter im text = (TextView) itemView.findViewById(R.id.text); text.setTypeface(ROBOTO_MEDIUM); image = (ImageView) itemView.findViewById(R.id.image); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - image.setBackground(getAttrDrawable(itemView.getContext(), android.R.attr.selectableItemBackgroundBorderless)); - } else { - image.setBackgroundResource(R.drawable.item_background); - } + setRoundItemBackground(image); image.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { diff --git a/Clover/app/src/main/java/org/floens/chan/ui/adapter/PinnedAdapter.java b/Clover/app/src/main/java/org/floens/chan/ui/adapter/PinnedAdapter.java deleted file mode 100644 index ad464dd1..00000000 --- a/Clover/app/src/main/java/org/floens/chan/ui/adapter/PinnedAdapter.java +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Clover - 4chan browser https://github.com/Floens/Clover/ - * Copyright (C) 2014 Floens - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.floens.chan.ui.adapter; - -import android.content.Context; -import android.os.Handler; -import android.os.Looper; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.BaseAdapter; -import android.widget.FrameLayout; -import android.widget.LinearLayout; -import android.widget.ListView; -import android.widget.ProgressBar; -import android.widget.TextView; - -import org.floens.chan.ChanApplication; -import org.floens.chan.R; -import org.floens.chan.core.settings.ChanSettings; -import org.floens.chan.core.model.Pin; -import org.floens.chan.ui.view.CustomNetworkImageView; - -import java.util.ArrayList; -import java.util.List; - -import static org.floens.chan.utils.AndroidUtils.dp; - -public class PinnedAdapter extends BaseAdapter { - private final static int VIEW_TYPE_ITEM = 0; - private final static int VIEW_TYPE_HEADER = 1; - - private Context context; - private ListView listView; - private List pins = new ArrayList<>(); - private boolean postInvalidated = false; - - public PinnedAdapter(Context context, ListView listView) { - this.context = context; - this.listView = listView; - } - - @Override - public int getCount() { - return pins.size() + 1; - } - - @Override - public int getViewTypeCount() { - return 2; - } - - @Override - public int getItemViewType(final int position) { - return position == 0 ? VIEW_TYPE_HEADER : VIEW_TYPE_ITEM; - } - - @Override - public Pin getItem(final int position) { - switch (getItemViewType(position)) { - case VIEW_TYPE_ITEM: - int itemPosition = position - 1; - if (itemPosition >= 0 && itemPosition < pins.size()) { - return pins.get(itemPosition); - } else { - return null; - } - case VIEW_TYPE_HEADER: - return null; - default: - return null; - } - } - - @Override - public long getItemId(int position) { - switch (getItemViewType(position)) { - case VIEW_TYPE_ITEM: - int itemPosition = position - 1; - if (itemPosition >= 0 && itemPosition < pins.size()) { - return pins.get(itemPosition).id; - } else { - return -1; - } - case VIEW_TYPE_HEADER: - return -1; - default: - return -1; - } - } - - @Override - public boolean hasStableIds() { - return true; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - switch (getItemViewType(position)) { - case VIEW_TYPE_ITEM: { - final Pin pin = getItem(position); - - if (convertView == null) { - convertView = LayoutInflater.from(context).inflate(R.layout.pin_item, null); - } - - CustomNetworkImageView imageView = (CustomNetworkImageView) convertView.findViewById(R.id.image); - if (pin.thumbnailUrl != null) { - imageView.setVisibility(View.VISIBLE); - imageView.setFadeIn(0); - imageView.forceImageDimensions(dp(48), dp(48)); - imageView.setImageUrl(pin.thumbnailUrl, ChanApplication.getVolleyImageLoader()); - } else { - imageView.setVisibility(View.GONE); - } - - ((TextView) convertView.findViewById(R.id.text)).setText(pin.loadable.title); - - FrameLayout timeContainer = (FrameLayout) convertView.findViewById(R.id.time_container); - FrameLayout countContainer = (FrameLayout) convertView.findViewById(R.id.pin_count_container); - if (ChanSettings.getWatchEnabled()) { - countContainer.setVisibility(View.VISIBLE); - - TextView timeView = (TextView) convertView.findViewById(R.id.time); - if (pin.watching && pin.getPinWatcher() != null && ChanSettings.getWatchCountdownVisibleEnabled()) { - timeContainer.setVisibility(View.VISIBLE); - long timeRaw = pin.getPinWatcher().getTimeUntilNextLoad(); - long time = 0; - if (timeRaw > 0) { - time = timeRaw / 1000L; - time = Math.min(9999, time); - } - - timeView.setText(Long.toString(time)); - - postInvalidate(); - } else { - timeContainer.setVisibility(View.GONE); - } - - TextView countView = (TextView) convertView.findViewById(R.id.pin_count); - ProgressBar loadView = (ProgressBar) convertView.findViewById(R.id.pin_load); - - if (pin.isError) { - countView.setText("Err"); - } else { - int count = pin.getNewPostCount(); - String total = Integer.toString(count); - if (count > 999) { - total = "1k+"; - } - countView.setText(total); - } - - if (pin.getPinWatcher() != null && pin.getPinWatcher().isLoading()) { - countView.setVisibility(View.GONE); - loadView.setVisibility(View.VISIBLE); - } else { - loadView.setVisibility(View.GONE); - countView.setVisibility(View.VISIBLE); - } - - countContainer.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { -// pin.toggleWatch(); - } - }); - - if (!pin.watching) { - countContainer.setBackgroundResource(R.drawable.pin_icon_gray); - } else if (pin.getNewQuoteCount() > 0) { - countContainer.setBackgroundResource(R.drawable.pin_icon_red); - } else { - countContainer.setBackgroundResource(R.drawable.pin_icon_blue); - } - } else { - timeContainer.setVisibility(View.GONE); - countContainer.setVisibility(View.GONE); - } - - return convertView; - } - case VIEW_TYPE_HEADER: { - if (convertView == null) { - convertView = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.pin_item_header, null); - ((TextView) convertView.findViewById(R.id.pin_header)).setText(R.string.drawer_pinned); - } - - return convertView; - } - default: - return null; - } - } - - public void reload() { - pins.clear(); - pins.addAll(ChanApplication.getWatchManager().getPins()); - - notifyDataSetChanged(); - } - - private void postInvalidate() { - if (!postInvalidated) { - postInvalidated = true; - new Handler(Looper.getMainLooper()).postDelayed(new Runnable() { - @Override - public void run() { - postInvalidated = false; - listView.invalidateViews(); - } - }, 1000); - } - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/animation/ScrollerRunnable.java b/Clover/app/src/main/java/org/floens/chan/ui/animation/ScrollerRunnable.java deleted file mode 100644 index 3e984f6e..00000000 --- a/Clover/app/src/main/java/org/floens/chan/ui/animation/ScrollerRunnable.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Clover - 4chan browser https://github.com/Floens/Clover/ - * Copyright (C) 2014 Floens - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.floens.chan.ui.animation; - -import android.view.View; -import android.view.ViewConfiguration; -import android.widget.AbsListView; -import android.widget.ListView; - -public class ScrollerRunnable implements Runnable { - private static final int SCROLL_DURATION = 300; - - private static final int MOVE_DOWN_POS = 1; - private static final int MOVE_UP_POS = 2; - - private final AbsListView mList; - - private int mMode; - private int mTargetPos; - private int mLastSeenPos; - private int mScrollDuration; - private final int mExtraScroll; - - public ScrollerRunnable(AbsListView listView) { - mList = listView; - mExtraScroll = ViewConfiguration.get(mList.getContext()).getScaledFadingEdgeLength(); - } - - public void start(int position) { - stop(); - - final int firstPos = mList.getFirstVisiblePosition(); - final int lastPos = firstPos + mList.getChildCount() - 1; - - int viewTravelCount; - if (position <= firstPos) { - viewTravelCount = firstPos - position + 1; - mMode = MOVE_UP_POS; - } else if (position >= lastPos) { - viewTravelCount = position - lastPos + 1; - mMode = MOVE_DOWN_POS; - } else { - // Already on screen, nothing to do - return; - } - - if (viewTravelCount > 0) { - mScrollDuration = SCROLL_DURATION / viewTravelCount; - } else { - mScrollDuration = SCROLL_DURATION; - } - mTargetPos = position; - mLastSeenPos = ListView.INVALID_POSITION; - - mList.post(this); - } - - void stop() { - mList.removeCallbacks(this); - } - - @Override - public void run() { - final int listHeight = mList.getHeight(); - final int firstPos = mList.getFirstVisiblePosition(); - - switch (mMode) { - case MOVE_DOWN_POS: { - final int lastViewIndex = mList.getChildCount() - 1; - final int lastPos = firstPos + lastViewIndex; - - if (lastViewIndex < 0) { - return; - } - - if (lastPos == mLastSeenPos) { - // No new views, let things keep going. - mList.post(this); - return; - } - - final View lastView = mList.getChildAt(lastViewIndex); - final int lastViewHeight = lastView.getHeight(); - final int lastViewTop = lastView.getTop(); - final int lastViewPixelsShowing = listHeight - lastViewTop; - final int extraScroll = lastPos < mList.getCount() - 1 ? mExtraScroll : mList.getPaddingBottom(); - - mList.smoothScrollBy(lastViewHeight - lastViewPixelsShowing + extraScroll, mScrollDuration); - - mLastSeenPos = lastPos; - if (lastPos < mTargetPos) { - mList.post(this); - } - break; - } - - case MOVE_UP_POS: { - if (firstPos == mLastSeenPos) { - // No new views, let things keep going. - mList.post(this); - return; - } - - final View firstView = mList.getChildAt(0); - if (firstView == null) { - return; - } - final int firstViewTop = firstView.getTop(); - final int extraScroll = firstPos > 0 ? mExtraScroll : mList.getPaddingTop(); - - mList.smoothScrollBy(firstViewTop - extraScroll, mScrollDuration); - - mLastSeenPos = firstPos; - - if (firstPos > mTargetPos) { - mList.post(this); - } - break; - } - - default: - break; - } - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/animation/SwipeDismissListViewTouchListener.java b/Clover/app/src/main/java/org/floens/chan/ui/animation/SwipeDismissListViewTouchListener.java deleted file mode 100644 index 367d1e1f..00000000 --- a/Clover/app/src/main/java/org/floens/chan/ui/animation/SwipeDismissListViewTouchListener.java +++ /dev/null @@ -1,409 +0,0 @@ -/* - * Copyright 2013 Google Inc. - * - * 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 org.floens.chan.ui.animation; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ValueAnimator; -import android.graphics.Rect; -import android.view.MotionEvent; -import android.view.VelocityTracker; -import android.view.View; -import android.view.ViewConfiguration; -import android.view.ViewGroup; -import android.widget.AbsListView; -import android.widget.ListView; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * A {@link android.view.View.OnTouchListener} that makes the list items in a - * {@link ListView} dismissable. {@link ListView} is given special treatment - * because by default it handles touches for its list items... i.e. it's in - * charge of drawing the pressed state (the list selector), handling list item - * clicks, etc. - *

- *

- * After creating the listener, the caller should also call - * {@link ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener)} - * , passing in the scroll listener returned by {@link #makeScrollListener()}. - * 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 - * scrolling. - *

- *

- *

- * Example usage: - *

- *

- *

- * SwipeDismissListViewTouchListener touchListener = new SwipeDismissListViewTouchListener(listView,
- *         new SwipeDismissListViewTouchListener.OnDismissCallback() {
- *             public void onDismiss(ListView listView, int[] reverseSortedPositions) {
- *                 for (int position : reverseSortedPositions) {
- *                     adapter.remove(adapter.getItem(position));
- *                 }
- *                 adapter.notifyDataSetChanged();
- *             }
- *         });
- * listView.setOnTouchListener(touchListener);
- * listView.setOnScrollListener(touchListener.makeScrollListener());
- * 
- *

- *

- * This class Requires API level 12 or later due to use of - * {@link android.view.ViewPropertyAnimator}. - *

- */ -public class SwipeDismissListViewTouchListener implements View.OnTouchListener { - // Cached ViewConfiguration and system-wide constant values - private int mSlop; - private final int mMinFlingVelocity; - private final int mMaxFlingVelocity; - private final long mAnimationTime; - - // Fixed properties - private final ListView mListView; - private final DismissCallbacks mCallbacks; - private int mViewWidth = 1; // 1 and not 0 to prevent dividing by zero - - // Transient properties - private final List mPendingDismisses = new ArrayList<>(); - private int mDismissAnimationRefCount = 0; - private float mDownX; - private boolean mSwiping; - private VelocityTracker mVelocityTracker; - private int mDownPosition; - private View mDownView; - private boolean mPaused; - - /** - * The callback interface used by {@link SwipeDismissListViewTouchListener} - * 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); - - /** - * 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 reverseSortedPositions An array of positions to dismiss, sorted in descending - * order for convenience. - */ - void onDismiss(ListView listView, int[] reverseSortedPositions); - } - - /** - * Constructs a new swipe-to-dismiss touch listener for the given list view. - * - * @param listView The list view whose items should be dismissable. - * @param callbacks The callback to trigger when the user has indicated that she - * would like to dismiss one or more list items. - */ - public SwipeDismissListViewTouchListener(ListView 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); - mListView = listView; - mCallbacks = callbacks; - } - - public int getSlop() { - return mSlop; - } - - public void setSlop(int slop) { - mSlop = slop; - } - - /** - * Enables or disables (pauses or resumes) watching for swipe-to-dismiss - * gestures. - * - * @param enabled Whether or not to watch for gestures. - */ - public void setEnabled(boolean enabled) { - mPaused = !enabled; - } - - /** - * Returns an {@link android.widget.AbsListView.OnScrollListener} to be - * added to the {@link ListView} using - * {@link ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener)} - * . 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 - * scrolling.

- * - * @see SwipeDismissListViewTouchListener - */ - public AbsListView.OnScrollListener makeScrollListener() { - return new AbsListView.OnScrollListener() { - @Override - public void onScrollStateChanged(AbsListView absListView, int scrollState) { - setEnabled(scrollState != AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL); - } - - @Override - public void onScroll(AbsListView absListView, int i, int i1, int i2) { - } - }; - } - - /** - * Manually cause the item at the given position to be dismissed (trigger - * the dismiss animation). - */ - public void dismiss(int position) { - dismiss(getViewForPosition(position), position, true); - } - - @Override - public boolean onTouch(View view, MotionEvent motionEvent) { - if (mViewWidth < 2) { - mViewWidth = mListView.getWidth(); - } - - mListView.requestDisallowInterceptTouchEvent(true); - - switch (motionEvent.getActionMasked()) { - case MotionEvent.ACTION_DOWN: { - if (mPaused) { - return false; - } - - // TODO: ensure this is a finger, and set a flag - - // Find the child view that was touched (perform a hit test) - Rect rect = new Rect(); - int childCount = mListView.getChildCount(); - 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++) { - child = mListView.getChildAt(i); - child.getHitRect(rect); - if (rect.contains(x, y)) { - mDownView = child; - break; - } - } - - if (mDownView != null) { - mDownX = motionEvent.getRawX(); - mDownPosition = mListView.getPositionForView(mDownView); - if (mCallbacks.canDismiss(mDownPosition)) { - mVelocityTracker = VelocityTracker.obtain(); - mVelocityTracker.addMovement(motionEvent); - } else { - mDownView = null; - } - } - 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) { - dismiss = true; - dismissRight = deltaX > 0; - } else if (mMinFlingVelocity <= absVelocityX && absVelocityX <= mMaxFlingVelocity - && absVelocityY < absVelocityX) { - // dismiss only if flinging in the same direction as dragging - dismiss = (velocityX < 0) == (deltaX < 0); - dismissRight = mVelocityTracker.getXVelocity() > 0; - } - if (dismiss) { - // dismiss - dismiss(mDownView, mDownPosition, dismissRight); - } else { - // cancel - mDownView.animate().translationX(0).alpha(1).setDuration(mAnimationTime).setListener(null); - } - mVelocityTracker.recycle(); - mVelocityTracker = null; - mDownX = 0; - mDownView = null; - mDownPosition = ListView.INVALID_POSITION; - 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; - mDownView = null; - mDownPosition = ListView.INVALID_POSITION; - mSwiping = false; - break; - } - - case MotionEvent.ACTION_MOVE: { - if (mVelocityTracker == null || mPaused) { - break; - } - - mVelocityTracker.addMovement(motionEvent); - float deltaX = motionEvent.getRawX() - mDownX; - if (Math.abs(deltaX) > mSlop) { - mSwiping = 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)); - mListView.onTouchEvent(cancelEvent); - cancelEvent.recycle(); - } - - if (mSwiping) { - mDownView.setTranslationX(deltaX); - mDownView.setAlpha(Math.max(0.15f, Math.min(1f, 1f - 2f * Math.abs(deltaX) / mViewWidth))); - return true; - } - break; - } - } - 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); - } - }); - } - - private View getViewForPosition(int position) { - int index = position - (mListView.getFirstVisiblePosition() - mListView.getHeaderViewsCount()); - return (index >= 0 && index < mListView.getChildCount()) ? mListView.getChildAt(index) : null; - } - - class PendingDismissData implements Comparable { - public int position; - public View view; - - public PendingDismissData(int position, View view) { - this.position = position; - this.view = view; - } - - @Override - public int compareTo(PendingDismissData other) { - // Sort by descending position - return other.position - position; - } - } - - private void performDismiss(final View dismissView, final int dismissPosition) { - // Animate the dismissed list item to zero-height and fire the dismiss callback when - // 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 ViewGroup.LayoutParams lp = dismissView.getLayoutParams(); - final int originalHeight = dismissView.getHeight(); - - ValueAnimator animator = ValueAnimator.ofInt(originalHeight, 1).setDuration(mAnimationTime); - - animator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - --mDismissAnimationRefCount; - if (mDismissAnimationRefCount == 0) { - // No active animations, process all pending dismisses. - // Sort by descending position - Collections.sort(mPendingDismisses); - - int[] dismissPositions = new int[mPendingDismisses.size()]; - for (int i = mPendingDismisses.size() - 1; i >= 0; i--) { - dismissPositions[i] = mPendingDismisses.get(i).position; - } - mCallbacks.onDismiss(mListView, dismissPositions); - - ViewGroup.LayoutParams lp; - for (PendingDismissData pendingDismiss : mPendingDismisses) { - // Reset view presentation - pendingDismiss.view.setAlpha(1f); - pendingDismiss.view.setTranslationX(0); - lp = pendingDismiss.view.getLayoutParams(); - lp.height = originalHeight; - pendingDismiss.view.setLayoutParams(lp); - } - - mPendingDismisses.clear(); - } - } - }); - - animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator valueAnimator) { - lp.height = (Integer) valueAnimator.getAnimatedValue(); - dismissView.setLayoutParams(lp); - } - }); - - mPendingDismisses.add(new PendingDismissData(dismissPosition, dismissView)); - animator.start(); - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/animation/ViewFlipperAnimations.java b/Clover/app/src/main/java/org/floens/chan/ui/animation/ViewFlipperAnimations.java deleted file mode 100644 index 54e7a0cf..00000000 --- a/Clover/app/src/main/java/org/floens/chan/ui/animation/ViewFlipperAnimations.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Clover - 4chan browser https://github.com/Floens/Clover/ - * Copyright (C) 2014 Floens - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.floens.chan.ui.animation; - -import android.view.animation.AccelerateDecelerateInterpolator; -import android.view.animation.Animation; -import android.view.animation.TranslateAnimation; - -/** - * Contains the TranslateAnimation's for a horizontal scrolling ViewFlipper. - */ -public class ViewFlipperAnimations { - public static TranslateAnimation BACK_IN; - public static TranslateAnimation BACK_OUT; - public static TranslateAnimation NEXT_IN; - public static TranslateAnimation NEXT_OUT; - - static { - // Setup the static TranslateAnimations for the ViewFlipper - BACK_IN = new TranslateAnimation(Animation.RELATIVE_TO_PARENT, -1f, Animation.RELATIVE_TO_PARENT, 0f, 0, 0f, 0, - 0f); - BACK_IN.setInterpolator(new AccelerateDecelerateInterpolator()); - BACK_IN.setDuration(300); - - BACK_OUT = new TranslateAnimation(Animation.RELATIVE_TO_PARENT, 0f, Animation.RELATIVE_TO_PARENT, 1f, 0, 0f, 0, - 0f); - BACK_OUT.setInterpolator(new AccelerateDecelerateInterpolator()); - BACK_OUT.setDuration(300); - - NEXT_IN = new TranslateAnimation(Animation.RELATIVE_TO_PARENT, 1f, Animation.RELATIVE_TO_PARENT, 0f, 0, 0f, 0, - 0f); - NEXT_IN.setInterpolator(new AccelerateDecelerateInterpolator()); - NEXT_IN.setDuration(300); - - NEXT_OUT = new TranslateAnimation(Animation.RELATIVE_TO_PARENT, 0f, Animation.RELATIVE_TO_PARENT, -1f, 0, 0f, - 0, 0f); - NEXT_OUT.setInterpolator(new AccelerateDecelerateInterpolator()); - NEXT_OUT.setDuration(300); - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/cell/PostCell.java b/Clover/app/src/main/java/org/floens/chan/ui/cell/PostCell.java index bcfa5d8e..2780f159 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/cell/PostCell.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/cell/PostCell.java @@ -1,10 +1,26 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.cell; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Typeface; import android.graphics.drawable.BitmapDrawable; -import android.os.Build; import android.support.annotation.NonNull; import android.text.Layout; import android.text.Spannable; @@ -29,7 +45,7 @@ import android.widget.TextView; import com.android.volley.VolleyError; import com.android.volley.toolbox.ImageLoader; -import org.floens.chan.ChanApplication; +import org.floens.chan.Chan; import org.floens.chan.R; import org.floens.chan.core.model.Loadable; import org.floens.chan.core.model.Post; @@ -46,8 +62,8 @@ import java.util.ArrayList; import java.util.List; import static org.floens.chan.utils.AndroidUtils.dp; -import static org.floens.chan.utils.AndroidUtils.getAttrDrawable; import static org.floens.chan.utils.AndroidUtils.getRes; +import static org.floens.chan.utils.AndroidUtils.setRoundItemBackground; import static org.floens.chan.utils.AndroidUtils.sp; public class PostCell extends RelativeLayout implements PostLinkable.Callback { @@ -132,17 +148,9 @@ public class PostCell extends RelativeLayout implements PostLinkable.Callback { replies.setTextSize(textSizeSp); replies.setPadding(paddingPx, 0, paddingPx, paddingPx); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - replies.setBackground(getAttrDrawable(getContext(), android.R.attr.selectableItemBackgroundBorderless)); - } else { - replies.setBackgroundResource(R.drawable.item_background); - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - options.setBackground(getAttrDrawable(getContext(), android.R.attr.selectableItemBackgroundBorderless)); - } else { - options.setBackgroundResource(R.drawable.item_background); - } + setRoundItemBackground(replies); + setRoundItemBackground(options); RelativeLayout.LayoutParams dividerParams = (LayoutParams) divider.getLayoutParams(); dividerParams.leftMargin = paddingPx; @@ -382,7 +390,7 @@ public class PostCell extends RelativeLayout implements PostLinkable.Callback { private void loadCountryIcon() { final Post requestedPost = post; - ChanApplication.getVolleyImageLoader().get(post.countryUrl, new ImageLoader.ImageListener() { + Chan.getVolleyImageLoader().get(post.countryUrl, new ImageLoader.ImageListener() { @Override public void onResponse(ImageLoader.ImageContainer response, boolean isImmediate) { if (response.getBitmap() != null && PostCell.this.post == requestedPost) { diff --git a/Clover/app/src/main/java/org/floens/chan/ui/cell/ThreadStatusCell.java b/Clover/app/src/main/java/org/floens/chan/ui/cell/ThreadStatusCell.java index 162879df..a1172287 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/cell/ThreadStatusCell.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/cell/ThreadStatusCell.java @@ -1,7 +1,23 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.cell; import android.content.Context; -import android.os.Build; import android.os.Handler; import android.os.Message; import android.util.AttributeSet; @@ -14,7 +30,6 @@ import org.floens.chan.core.model.ChanThread; import org.floens.chan.core.model.Post; import static org.floens.chan.utils.AndroidUtils.ROBOTO_MEDIUM; -import static org.floens.chan.utils.AndroidUtils.getAttrDrawable; public class ThreadStatusCell extends LinearLayout implements View.OnClickListener { private static final int UPDATE_INTERVAL = 1000; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/AdvancedSettingsController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/AdvancedSettingsController.java index f0b861a4..38c880bb 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/AdvancedSettingsController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/AdvancedSettingsController.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.controller; import android.app.Activity; @@ -42,10 +59,11 @@ public class AdvancedSettingsController extends SettingsController { private void populatePreferences() { SettingsGroup settings = new SettingsGroup(string(R.string.settings_group_advanced)); + // TODO change this to a presenting controller saveLocation = (LinkSettingView) settings.add(new LinkSettingView(this, string(R.string.setting_save_folder), null, new View.OnClickListener() { @Override public void onClick(View v) { - File dir = ChanSettings.getImageSaveDirectory(); + File dir = new File(ChanSettings.saveLocation.get()); if (!dir.mkdirs() && !dir.isDirectory()) { new AlertDialog.Builder(context).setMessage(R.string.setting_save_folder_error_create_folder).show(); } else { @@ -66,8 +84,8 @@ public class AdvancedSettingsController extends SettingsController { settings.add(new BooleanSettingView(this, ChanSettings.shareUrl, string(R.string.setting_share_url), string(R.string.setting_share_url_description))); settings.add(new BooleanSettingView(this, ChanSettings.networkHttps, string(R.string.setting_network_https), string(R.string.setting_network_https_description))); settings.add(new BooleanSettingView(this, ChanSettings.forcePhoneLayout, string(R.string.setting_force_phone_layout), null)); - settings.add(new BooleanSettingView(this, ChanSettings.anonymize, string(R.string.preference_anonymize), null)); - settings.add(new BooleanSettingView(this, ChanSettings.anonymizeIds, string(R.string.preference_anonymize_ids), null)); + settings.add(new BooleanSettingView(this, ChanSettings.anonymize, string(R.string.setting_anonymize), null)); + settings.add(new BooleanSettingView(this, ChanSettings.anonymizeIds, string(R.string.setting_anonymize_ids), null)); settings.add(new BooleanSettingView(this, ChanSettings.repliesButtonsBottom, string(R.string.setting_buttons_bottom), null)); settings.add(new BooleanSettingView(this, ChanSettings.confirmExit, string(R.string.setting_confirm_exit), null)); diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/BoardEditController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/BoardEditController.java index fdd7a4b8..b0c0f310 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/BoardEditController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/BoardEditController.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.controller; import android.app.AlertDialog; @@ -19,7 +36,7 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; -import org.floens.chan.ChanApplication; +import org.floens.chan.Chan; import org.floens.chan.R; import org.floens.chan.controller.Controller; import org.floens.chan.core.manager.BoardManager; @@ -40,7 +57,7 @@ import static org.floens.chan.utils.AndroidUtils.dp; public class BoardEditController extends Controller implements SwipeListener.Callback, ToolbarMenuItem.ToolbarMenuItemCallback { private static final int ADD_ID = 1; - private final BoardManager boardManager = ChanApplication.getBoardManager(); + private final BoardManager boardManager = Chan.getBoardManager(); private RecyclerView recyclerView; private BoardEditAdapter adapter; @@ -173,7 +190,7 @@ public class BoardEditController extends Controller implements SwipeListener.Cal } // Normal add - List all = ChanApplication.getBoardManager().getAllBoards(); + List all = Chan.getBoardManager().getAllBoards(); for (Board board : all) { if (board.value.equals(value)) { board.saved = true; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/BrowseController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/BrowseController.java index 1fa42095..a4b164c4 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/BrowseController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/BrowseController.java @@ -25,7 +25,7 @@ import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; -import org.floens.chan.ChanApplication; +import org.floens.chan.Chan; import org.floens.chan.R; import org.floens.chan.chan.ChanUrls; import org.floens.chan.core.manager.BoardManager; @@ -68,8 +68,8 @@ public class BrowseController extends ThreadController implements ToolbarMenuIte navigationItem.menu = menu; navigationItem.hasBack = false; - menu.addItem(new ToolbarMenuItem(context, this, REFRESH_ID, R.drawable.ic_action_refresh)); - menu.addItem(new ToolbarMenuItem(context, this, POST_ID, R.drawable.ic_action_write)); + menu.addItem(new ToolbarMenuItem(context, this, REFRESH_ID, R.drawable.ic_refresh_white_24dp)); + menu.addItem(new ToolbarMenuItem(context, this, POST_ID, R.drawable.ic_create_white_24dp)); ToolbarMenuItem overflow = menu.createOverflow(this); @@ -80,7 +80,7 @@ public class BrowseController extends ThreadController implements ToolbarMenuIte overflow.setSubMenu(new FloatingMenu(context, overflow.getView(), items)); - loadBoard(ChanApplication.getBoardManager().getSavedBoards().get(0)); + loadBoard(Chan.getBoardManager().getSavedBoards().get(0)); } @Override @@ -168,7 +168,7 @@ public class BrowseController extends ThreadController implements ToolbarMenuIte } private void loadBoards() { - List boards = ChanApplication.getBoardManager().getSavedBoards(); + List boards = Chan.getBoardManager().getSavedBoards(); boardItems = new ArrayList<>(); for (Board board : boards) { FloatingMenuItem item = new FloatingMenuItemBoard(board); @@ -222,7 +222,7 @@ public class BrowseController extends ThreadController implements ToolbarMenuIte if (position >= 0 && position < items.size()) { return items.get(position).getText(); } else { - return context.getString(R.string.board_select_add); + return context.getString(R.string.thread_board_select_add); } } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/DeveloperSettingsController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/DeveloperSettingsController.java index 2b4e27e6..6164e112 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/DeveloperSettingsController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/DeveloperSettingsController.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.controller; import android.content.Context; @@ -7,7 +24,7 @@ import android.widget.LinearLayout; import android.widget.ScrollView; import android.widget.TextView; -import org.floens.chan.ChanApplication; +import org.floens.chan.Chan; import org.floens.chan.R; import org.floens.chan.controller.Controller; import org.floens.chan.core.model.SavedReply; @@ -53,7 +70,7 @@ public class DeveloperSettingsController extends Controller { resetDbButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - ChanApplication.getDatabaseManager().reset(); + Chan.getDatabaseManager().reset(); System.exit(0); } }); @@ -68,7 +85,7 @@ public class DeveloperSettingsController extends Controller { int j = 0; for (int i = 0; i < 100; i++) { j += r.nextInt(10000); - ChanApplication.getDatabaseManager().saveReply(new SavedReply("g", j, "pass")); + Chan.getDatabaseManager().saveReply(new SavedReply("g", j, "pass")); } setDbSummary(); } @@ -80,7 +97,7 @@ public class DeveloperSettingsController extends Controller { trimSavedReply.setOnClickListener(new View.OnClickListener() { @Override public void onClick(final View v) { - ChanApplication.getDatabaseManager().trimSavedRepliesTable(10); + Chan.getDatabaseManager().trimSavedRepliesTable(10); setDbSummary(); } }); @@ -95,7 +112,7 @@ public class DeveloperSettingsController extends Controller { private void setDbSummary() { String dbSummary = ""; dbSummary += "Database summary:\n"; - dbSummary += ChanApplication.getDatabaseManager().getSummary(); + dbSummary += Chan.getDatabaseManager().getSummary(); summaryText.setText(dbSummary); } } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/ImageViewerController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/ImageViewerController.java index 651e01ed..e7db17f7 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/ImageViewerController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/ImageViewerController.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.controller; import android.animation.Animator; @@ -5,6 +22,7 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; +import android.annotation.SuppressLint; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; @@ -28,7 +46,7 @@ import com.android.volley.VolleyError; import com.android.volley.toolbox.ImageLoader; import com.davemorrissey.labs.subscaleview.ImageViewState; -import org.floens.chan.ChanApplication; +import org.floens.chan.Chan; import org.floens.chan.R; import org.floens.chan.chan.ImageSearch; import org.floens.chan.controller.Controller; @@ -249,6 +267,7 @@ public class ImageViewerController extends Controller implements View.OnClickLis if (ChanSettings.videoErrorIgnore.get()) { Toast.makeText(context, R.string.image_open_failed, Toast.LENGTH_SHORT).show(); } else { + @SuppressLint("InflateParams") View notice = LayoutInflater.from(context).inflate(R.layout.dialog_video_error, null); final CheckBox dontShowAgain = (CheckBox) notice.findViewById(R.id.checkbox); @@ -309,7 +328,7 @@ public class ImageViewerController extends Controller implements View.OnClickLis } }); - ChanApplication.getVolleyImageLoader().get(postImage.thumbnailUrl, new ImageLoader.ImageListener() { + Chan.getVolleyImageLoader().get(postImage.thumbnailUrl, new ImageLoader.ImageListener() { @Override public void onErrorResponse(VolleyError error) { Log.e(TAG, "onErrorResponse for preview in transition in ImageViewerController, cannot show correct transition bitmap"); @@ -331,7 +350,7 @@ public class ImageViewerController extends Controller implements View.OnClickLis return; } - ChanApplication.getVolleyImageLoader().get(postImage.thumbnailUrl, new ImageLoader.ImageListener() { + Chan.getVolleyImageLoader().get(postImage.thumbnailUrl, new ImageLoader.ImageListener() { @Override public void onErrorResponse(VolleyError error) { Log.e(TAG, "onErrorResponse for preview out transition in ImageViewerController, cannot show correct transition bitmap"); diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/ImageViewerNavigationController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/ImageViewerNavigationController.java index 0e89789a..d9008412 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/ImageViewerNavigationController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/ImageViewerNavigationController.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.controller; import android.content.Context; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/LicensesController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/LicensesController.java index 257864f6..baaa1e58 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/LicensesController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/LicensesController.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.controller; import android.content.Context; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/PassSettingsController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/PassSettingsController.java index d0432671..6ffcec71 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/PassSettingsController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/PassSettingsController.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.controller; import android.app.AlertDialog; @@ -12,7 +29,7 @@ import android.widget.EditText; import android.widget.LinearLayout; import android.widget.TextView; -import org.floens.chan.ChanApplication; +import org.floens.chan.Chan; import org.floens.chan.R; import org.floens.chan.controller.Controller; import org.floens.chan.core.reply.ReplyManager; @@ -100,7 +117,7 @@ public class PassSettingsController extends Controller implements View.OnClickLi ChanSettings.passToken.set(inputToken.getText().toString()); ChanSettings.passPin.set(inputPin.getText().toString()); - ChanApplication.getReplyManager().postPass(ChanSettings.passToken.get(), ChanSettings.passPin.get(), new ReplyManager.PassListener() { + Chan.getReplyManager().postPass(ChanSettings.passToken.get(), ChanSettings.passPin.get(), new ReplyManager.PassListener() { @Override public void onResponse(ReplyManager.PassResponse response) { if (response.isError) { diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/PostRepliesController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/PostRepliesController.java index 896d652d..bdf7a4f1 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/PostRepliesController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/PostRepliesController.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.controller; import android.animation.ValueAnimator; @@ -24,7 +41,6 @@ import org.floens.chan.core.settings.ChanSettings; import org.floens.chan.ui.cell.PostCell; import org.floens.chan.ui.helper.PostPopupHelper; import org.floens.chan.ui.view.LoadView; -import org.floens.chan.ui.view.PostView; import org.floens.chan.ui.view.ThumbnailView; import org.floens.chan.utils.ThemeHelper; @@ -133,8 +149,8 @@ public class PostRepliesController extends Controller { }); if (!ThemeHelper.getInstance().getTheme().isLightTheme) { - ((TextView) dataView.findViewById(R.id.replies_back_icon)).setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_action_back_dark, 0, 0, 0); - ((TextView) dataView.findViewById(R.id.replies_close_icon)).setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_action_done_dark, 0, 0, 0); + ((TextView) dataView.findViewById(R.id.replies_back_icon)).setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_arrow_back_white_24dp, 0, 0, 0); + ((TextView) dataView.findViewById(R.id.replies_close_icon)).setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_done_white_24dp, 0, 0, 0); dataView.findViewById(R.id.container).setBackgroundResource(R.drawable.dialog_full_dark); } @@ -142,24 +158,15 @@ public class PostRepliesController extends Controller { @Override public View getView(int position, View convertView, ViewGroup parent) { PostCell postCell; - if (convertView instanceof PostView) { + if (convertView instanceof PostCell) { postCell = (PostCell) convertView; } else { - postCell = (PostCell) LayoutInflater.from(parent.getContext()).inflate(R.layout.cell_post, parent, false); + postCell = (PostCell) LayoutInflater.from(parent.getContext()).inflate(R.layout.cell_post, parent, false); } final Post p = getItem(position); postCell.setPost(p, presenter, false, data.forPost.no); -// postView.setPost(p, presenter, false); -// postView.setHighlightQuotesWithNo(data.forPost.no); - /*postCell.setOnClickListeners(new View.OnClickListener() { - @Override - public void onClick(View v) { - postPopupHelper.postClicked(p); - } - });*/ - return postCell; } }; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/RootNavigationController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/RootNavigationController.java index f4d1e67b..21c9d13e 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/RootNavigationController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/RootNavigationController.java @@ -25,7 +25,7 @@ import android.view.Gravity; import android.view.View; import android.widget.FrameLayout; -import org.floens.chan.ChanApplication; +import org.floens.chan.Chan; import org.floens.chan.R; import org.floens.chan.controller.Controller; import org.floens.chan.controller.ControllerTransition; @@ -72,7 +72,7 @@ public class RootNavigationController extends NavigationController implements Pi new SwipeListener(context, recyclerView, pinAdapter); - pinAdapter.onPinsChanged(ChanApplication.getWatchManager().getPins()); + pinAdapter.onPinsChanged(Chan.getWatchManager().getPins()); toolbar.setCallback(this); @@ -162,7 +162,7 @@ public class RootNavigationController extends NavigationController implements Pi @Override public void onWatchCountClicked(Pin pin) { - ChanApplication.getWatchManager().toggleWatch(pin); + Chan.getWatchManager().toggleWatch(pin); } @Override diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/ThreadController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/ThreadController.java index 1813a228..245c8662 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/ThreadController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/ThreadController.java @@ -1,8 +1,25 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.controller; import android.content.Context; -import org.floens.chan.ChanApplication; +import org.floens.chan.Chan; import org.floens.chan.controller.Controller; import org.floens.chan.core.model.Loadable; import org.floens.chan.core.model.PostImage; @@ -45,7 +62,7 @@ public abstract class ThreadController extends Controller implements ThreadLayou return threadLayout.onBack(); } - public void onEvent(ChanApplication.ForegroundChangedMessage message) { + public void onEvent(Chan.ForegroundChangedMessage message) { threadLayout.getPresenter().onForegroundChanged(message.inForeground); } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/ViewThreadController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/ViewThreadController.java index 32ba1bcc..81c50347 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/ViewThreadController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/ViewThreadController.java @@ -21,7 +21,7 @@ import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; -import org.floens.chan.ChanApplication; +import org.floens.chan.Chan; import org.floens.chan.R; import org.floens.chan.chan.ChanUrls; import org.floens.chan.core.manager.WatchManager; @@ -62,8 +62,8 @@ public class ViewThreadController extends ThreadController implements ThreadLayo navigationItem.hasDrawer = true; navigationItem.menu = new ToolbarMenu(context); - navigationItem.menu.addItem(new ToolbarMenuItem(context, this, POST_ID, R.drawable.ic_action_write)); - pinItem = navigationItem.menu.addItem(new ToolbarMenuItem(context, this, PIN_ID, R.drawable.ic_bookmark)); + navigationItem.menu.addItem(new ToolbarMenuItem(context, this, POST_ID, R.drawable.ic_create_white_24dp)); + pinItem = navigationItem.menu.addItem(new ToolbarMenuItem(context, this, PIN_ID, R.drawable.ic_bookmark_outline_white_24dp)); navigationItem.createOverflow(context, this, Arrays.asList( new FloatingMenuItem(REFRESH_ID, context.getString(R.string.action_reload)), new FloatingMenuItem(SEARCH_ID, context.getString(R.string.action_search)), @@ -177,11 +177,11 @@ public class ViewThreadController extends ThreadController implements ThreadLayo } private void setPinIconState() { - WatchManager wm = ChanApplication.getWatchManager(); + WatchManager wm = Chan.getWatchManager(); setPinIconState(wm.findPinByLoadable(loadable) != null); } private void setPinIconState(boolean pinned) { - pinItem.setImage(pinned ? R.drawable.ic_bookmark_filled : R.drawable.ic_bookmark); + pinItem.setImage(pinned ? R.drawable.ic_bookmark_white_24dp : R.drawable.ic_bookmark_outline_white_24dp); } } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/WatchSettingsController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/WatchSettingsController.java index 7592c710..3398f629 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/WatchSettingsController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/WatchSettingsController.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.controller; import android.content.Context; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/drawable/DropdownArrowDrawable.java b/Clover/app/src/main/java/org/floens/chan/ui/drawable/DropdownArrowDrawable.java index 37e05f8b..49a5f1cb 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/drawable/DropdownArrowDrawable.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/drawable/DropdownArrowDrawable.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.drawable; import android.graphics.Canvas; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/drawable/ThumbDrawable.java b/Clover/app/src/main/java/org/floens/chan/ui/drawable/ThumbDrawable.java index 5f6c1031..1e97c808 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/drawable/ThumbDrawable.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/drawable/ThumbDrawable.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.drawable; import android.graphics.Canvas; @@ -9,7 +26,6 @@ import android.graphics.drawable.Drawable; import static org.floens.chan.utils.AndroidUtils.dp; - public class ThumbDrawable extends Drawable { private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); private Path path = new Path(); diff --git a/Clover/app/src/main/java/org/floens/chan/ui/fragment/FolderPickFragment.java b/Clover/app/src/main/java/org/floens/chan/ui/fragment/FolderPickFragment.java index 1e02bd84..2f7dbe0f 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/fragment/FolderPickFragment.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/fragment/FolderPickFragment.java @@ -71,7 +71,7 @@ public class FolderPickFragment extends DialogFragment { return null; } - View container = inflater.inflate(R.layout.folder_pick, parent); + View container = inflater.inflate(R.layout.fragment_folder_pick, parent); statusPath = (TextView) container.findViewById(R.id.folder_status); listView = (ListView) container.findViewById(R.id.folder_list); @@ -94,8 +94,8 @@ public class FolderPickFragment extends DialogFragment { }); if (!ThemeHelper.getInstance().getTheme().isLightTheme) { - ((TextView) container.findViewById(R.id.pick_back_icon)).setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_action_cancel_dark, 0, 0, 0); - ((TextView) container.findViewById(R.id.pick_ok_icon)).setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_action_done_dark, 0, 0, 0); + ((TextView) container.findViewById(R.id.pick_back_icon)).setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_arrow_back_white_24dp, 0, 0, 0); + ((TextView) container.findViewById(R.id.pick_ok_icon)).setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_done_white_24dp, 0, 0, 0); } adapter = new ArrayAdapter(inflater.getContext(), 0) { diff --git a/Clover/app/src/main/java/org/floens/chan/ui/fragment/ImageViewFragment.java b/Clover/app/src/main/java/org/floens/chan/ui/fragment/ImageViewFragment.java deleted file mode 100644 index 35434b4a..00000000 --- a/Clover/app/src/main/java/org/floens/chan/ui/fragment/ImageViewFragment.java +++ /dev/null @@ -1,354 +0,0 @@ -/* - * Clover - 4chan browser https://github.com/Floens/Clover/ - * Copyright (C) 2014 Floens - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.floens.chan.ui.fragment; - -import android.app.AlertDialog; -import android.app.Fragment; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.CheckBox; -import android.widget.LinearLayout; -import android.widget.TextView; -import android.widget.Toast; -import android.widget.VideoView; - -import org.floens.chan.R; -import org.floens.chan.chan.ImageSearch; -import org.floens.chan.core.model.Post; -import org.floens.chan.core.settings.ChanSettings; -import org.floens.chan.ui.activity.ImageViewActivity; -import org.floens.chan.ui.adapter.ImageViewAdapter; -import org.floens.chan.ui.view.MultiImageView; -import org.floens.chan.ui.view.MultiImageView.Callback; -import org.floens.chan.utils.AndroidUtils; -import org.floens.chan.utils.ImageSaver; - -import static org.floens.chan.utils.AndroidUtils.dp; - -public class ImageViewFragment extends Fragment implements Callback { - private Context context; - private ImageViewActivity activity; - - private MultiImageView imageView; - - private Post post; - private boolean showProgressBar = true; - private boolean isVideo = false; - private boolean videoVisible = false; - private boolean videoSetIconToPause = false; - private boolean tapToLoad = false; - private boolean loaded = false; - - private long progressCurrent; - private long progressTotal; - private boolean progressDone; - - public static ImageViewFragment newInstance(Post post, ImageViewActivity activity, int index) { - ImageViewFragment imageViewFragment = new ImageViewFragment(); - imageViewFragment.post = post; - imageViewFragment.activity = activity; - - return imageViewFragment; - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - if (post == null) { - // No restoring - return null; - } else { - context = inflater.getContext(); - - imageView = new MultiImageView(context); - imageView.setCallback(this); - int padding = getResources().getDimensionPixelSize(R.dimen.image_view_padding); - imageView.setPadding(padding, padding, padding, padding); - - return imageView; - } - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - // No restoring - if (post != null) { - if (!post.hasImage) { - throw new IllegalArgumentException("Post has no image"); - } - - // After layout has been done so getWidth & getHeight don't return 0 - imageView.post(new Runnable() { - @Override - public void run() { - // When the viewpager is created, it starts loading the first two views, - // then we set a position to the viewpager and it loads three more views! - // Check for these unused views here to avoid unnecessary loads - if (imageView.getWidth() == 0 || imageView.getHeight() == 0) - return; - - imageView.setThumbnail(post.thumbnailUrl); - - if (ChanSettings.getImageAutoLoad() && !post.spoiler) { - load(); - } else { - tapToLoad = true; - showProgressBar(false); - - if (post.ext.equals("webm")) { - isVideo = true; - activity.invalidateActionBar(); - } - } - } - }); - } - } - - private void load() { - if (loaded) return; - loaded = true; - - switch (post.ext) { - case "gif": - imageView.setGif(post.imageUrl); - break; - case "webm": - isVideo = true; - activity.invalidateActionBar(); - showProgressBar(false); - - if (tapToLoad) { - if (!videoVisible) { - startVideo(); - } else { - if (imageView.getVideoView() != null) { - imageView.getVideoView().start(); - } - } - } - break; - default: - imageView.setBigImage(post.imageUrl); - break; - } - - } - - @Override - public void onSaveInstanceState(Bundle bundle) { - // https://code.google.com/p/android/issues/detail?id=19917 - bundle.putString("bug_19917", "bug_19917"); - super.onSaveInstanceState(bundle); - } - - @Override - public void onDestroy() { - super.onDestroy(); - - if (imageView != null) { - imageView.cancelLoad(); - } - } - - public void onSelected(ImageViewAdapter adapter, int position) { - activity.setProgressBarIndeterminateVisibility(showProgressBar); - - String filename = post.filename + "." + post.ext; - activity.getSupportActionBar().setTitle(filename); - - String text = (position + 1) + "/" + adapter.getCount(); - activity.getSupportActionBar().setSubtitle(text); - - activity.invalidateActionBar(); - - if (isVideo && ChanSettings.getVideoAutoPlay() && imageView != null) { - if (!videoVisible) { - startVideo(); - } else { - if (imageView.getVideoView() != null) { - imageView.getVideoView().start(); - } - } - } - - activity.setProgressBar(progressCurrent, progressTotal, progressDone); - } - - public void onDeselected() { - if (imageView != null && imageView.getVideoView() != null) { - imageView.getVideoView().pause(); - } - } - - public void onPrepareOptionsMenu(Menu menu) { - MenuItem item = menu.findItem(R.id.action_image_play_state); - item.setVisible(isVideo); - item.setEnabled(isVideo); - - if (imageView != null) { - VideoView view = imageView.getVideoView(); - if (view != null) { - item.setIcon((videoSetIconToPause || view.isPlaying()) ? R.drawable.ic_action_pause - : R.drawable.ic_action_play); - videoSetIconToPause = false; - } - } - } - - public void customOnOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.action_image_play_state: - if (!videoVisible) { - startVideo(); - } else { - VideoView view = imageView.getVideoView(); - if (view != null) { - if (!view.isPlaying()) { - view.start(); - } else { - view.pause(); - } - } - } - - activity.invalidateActionBar(); - break; - case R.id.action_open_browser: - AndroidUtils.openLink(post.imageUrl); - break; - case R.id.action_image_save: - case R.id.action_share: - if (ChanSettings.getImageShareUrl()) { - shareImageUrl(post.imageUrl); - } else { - ImageSaver.getInstance().saveImage(context, post.imageUrl, - ChanSettings.getImageSaveOriginalFilename() ? Long.toString(post.tim) : post.filename, post.ext, - item.getItemId() == R.id.action_share); - } - break; - default: - // Search if it was an ImageSearch item - for (ImageSearch engine : ImageSearch.engines) { - if (item.getItemId() == engine.getId()) { - AndroidUtils.openLink(engine.getUrl(post.imageUrl)); - break; - } - } - - break; - } - } - - private void shareImageUrl(String url) { - Intent intent = new Intent(Intent.ACTION_SEND); - intent.setType("text/plain"); - intent.putExtra(Intent.EXTRA_TEXT, url); - context.startActivity(Intent.createChooser(intent, context.getString(R.string.action_share))); - } - - public void onVideoError(MultiImageView view) { - if (ChanSettings.getVideoErrorIgnore()) { - Toast.makeText(context, R.string.image_open_failed, Toast.LENGTH_SHORT).show(); - } else { - showVideoWarning(); - } - } - - @Override - public void onModeLoaded(MultiImageView multiImageView, MultiImageView.Mode mode) { - - } - - private void showVideoWarning() { - LinearLayout notice = new LinearLayout(context); - notice.setOrientation(LinearLayout.VERTICAL); - - TextView noticeText = new TextView(context); - noticeText.setText(R.string.video_playback_warning); - noticeText.setTextSize(16f); - notice.addView(noticeText, AndroidUtils.MATCH_WRAP_PARAMS); - - final CheckBox dontShowAgain = new CheckBox(context); - dontShowAgain.setText(R.string.video_playback_ignore); - notice.addView(dontShowAgain, AndroidUtils.MATCH_WRAP_PARAMS); - - int padding = dp(16f); - notice.setPadding(padding, padding, padding, padding); - - new AlertDialog.Builder(context) - .setTitle(R.string.video_playback_warning_title) - .setView(notice) - .setNeutralButton(R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - if (dontShowAgain.isChecked()) { - ChanSettings.setVideoErrorIgnore(true); - } - } - }) - .setCancelable(false) - .show(); - } - - private void startVideo() { - if (videoVisible) return; - videoVisible = true; - - imageView.setVideo(post.imageUrl); - } - - public void showProgressBar(boolean e) { - showProgressBar = e; - activity.updateActionBarIfSelected(this); - } - - @Override - public void onTap(MultiImageView view) { - if (tapToLoad) { - if (loaded) { - activity.finish(); - } else { - load(); - } - } else { - activity.finish(); - } - } - - @Override - public void showProgress(MultiImageView view, boolean progress) { - showProgressBar(progress); - } - - @Override - public void onProgress(MultiImageView view, long current, long total) { - progressCurrent = current; - progressTotal = total; - progressDone = true; - activity.updateActionBarIfSelected(this); - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/fragment/PostRepliesFragment.java b/Clover/app/src/main/java/org/floens/chan/ui/fragment/PostRepliesFragment.java deleted file mode 100644 index 3ca1aafe..00000000 --- a/Clover/app/src/main/java/org/floens/chan/ui/fragment/PostRepliesFragment.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Clover - 4chan browser https://github.com/Floens/Clover/ - * Copyright (C) 2014 Floens - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.floens.chan.ui.fragment; - -import android.app.Activity; -import android.app.DialogFragment; -import android.content.DialogInterface; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AbsListView; -import android.widget.ArrayAdapter; -import android.widget.ListView; -import android.widget.TextView; - -import org.floens.chan.R; -import org.floens.chan.core.settings.ChanSettings; -import org.floens.chan.core.model.Post; -import org.floens.chan.core.presenter.ThreadPresenter; -import org.floens.chan.ui.helper.PostPopupHelper; -import org.floens.chan.ui.view.PostView; -import org.floens.chan.utils.ThemeHelper; - -/** - * A DialogFragment that shows a list of posts. Use the newInstance method for - * instantiating. - */ -public class PostRepliesFragment extends DialogFragment { - private ListView listView; - - private Activity activity; - private PostPopupHelper.RepliesData repliesData; - private PostPopupHelper postPopupHelper; - private ThreadPresenter presenter; - - public static PostRepliesFragment newInstance(PostPopupHelper.RepliesData repliesData, PostPopupHelper postPopupHelper, ThreadPresenter presenter) { - PostRepliesFragment fragment = new PostRepliesFragment(); - - fragment.repliesData = repliesData; - fragment.postPopupHelper = postPopupHelper; - fragment.presenter = presenter; - return fragment; - } - - public void dismissNoCallback() { - postPopupHelper = null; - dismiss(); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setStyle(STYLE_NO_TITLE, 0); - } - - @Override - public void onDismiss(DialogInterface dialog) { - super.onDismiss(dialog); - - if (postPopupHelper != null) { -// postPopupHelper.onPostRepliesPop(); - } - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup unused, Bundle savedInstanceState) { - View container; - if (ChanSettings.getReplyButtonsBottom()) { - container = inflater.inflate(R.layout.post_replies_bottombuttons, null); - } else { - container = inflater.inflate(R.layout.post_replies, null); - } - - listView = (ListView) container.findViewById(R.id.post_list); - - container.findViewById(R.id.replies_back).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - dismiss(); - } - }); - - container.findViewById(R.id.replies_close).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (postPopupHelper != null) { -// postPopupHelper.closeAllPostFragments(); - } - } - }); - - if (!ThemeHelper.getInstance().getTheme().isLightTheme) { - ((TextView) container.findViewById(R.id.replies_back_icon)).setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_action_back_dark, 0, 0, 0); - ((TextView) container.findViewById(R.id.replies_close_icon)).setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_action_done_dark, 0, 0, 0); - } - - return container; - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - activity = getActivity(); - - if (repliesData == null) { - // Restoring from background. - dismiss(); - } else { - ArrayAdapter adapter = new ArrayAdapter(activity, 0) { - @Override - public View getView(int position, View convertView, ViewGroup parent) { - PostView postView; - if (convertView instanceof PostView) { - postView = (PostView) convertView; - } else { - postView = new PostView(activity); - } - - final Post p = getItem(position); - -// postView.setPost(p, presenter, false); -// postView.setHighlightQuotesWithNo(repliesData.forPost.no); - postView.setOnClickListeners(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (postPopupHelper != null) { - postPopupHelper.postClicked(p); - } - dismiss(); - } - }); - - return postView; - } - }; - - adapter.addAll(repliesData.posts); - listView.setAdapter(adapter); - - listView.setSelectionFromTop(repliesData.listViewIndex, repliesData.listViewTop); - listView.setOnScrollListener(new AbsListView.OnScrollListener() { - @Override - public void onScrollStateChanged(AbsListView view, int scrollState) { - } - - @Override - public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { - if (repliesData != null) { - repliesData.listViewIndex = view.getFirstVisiblePosition(); - View v = view.getChildAt(0); - repliesData.listViewTop = (v == null) ? 0 : v.getTop(); - } - } - }); - } - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/fragment/ReplyFragment.java b/Clover/app/src/main/java/org/floens/chan/ui/fragment/ReplyFragment.java deleted file mode 100644 index 2f1c0368..00000000 --- a/Clover/app/src/main/java/org/floens/chan/ui/fragment/ReplyFragment.java +++ /dev/null @@ -1,609 +0,0 @@ -/* - * Clover - 4chan browser https://github.com/Floens/Clover/ - * Copyright (C) 2014 Floens - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.floens.chan.ui.fragment; - -import android.app.Dialog; -import android.app.DialogFragment; -import android.content.DialogInterface; -import android.graphics.Bitmap; -import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; -import android.text.Editable; -import android.text.TextUtils; -import android.text.TextWatcher; -import android.view.Gravity; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.WindowManager; -import android.webkit.WebSettings; -import android.webkit.WebView; -import android.widget.Button; -import android.widget.CheckBox; -import android.widget.EditText; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.TextView; -import android.widget.Toast; -import android.widget.ViewFlipper; - -import org.floens.chan.ChanApplication; -import org.floens.chan.R; -import org.floens.chan.chan.ChanUrls; -import org.floens.chan.core.reply.ReplyManager; -import org.floens.chan.core.model.Board; -import org.floens.chan.core.model.Loadable; -import org.floens.chan.core.model.Reply; -import org.floens.chan.core.settings.ChanSettings; -import org.floens.chan.ui.animation.ViewFlipperAnimations; -import org.floens.chan.ui.layout.CaptchaLayout; -import org.floens.chan.ui.view.LoadView; -import org.floens.chan.utils.AndroidUtils; -import org.floens.chan.utils.ImageDecoder; -import org.floens.chan.utils.Logger; -import org.floens.chan.utils.ThemeHelper; - -import java.io.File; - -import static org.floens.chan.utils.AndroidUtils.dp; - -public class ReplyFragment extends DialogFragment implements CaptchaLayout.CaptchaCallback { - private static final String TAG = "ReplyFragment"; - - private int page = 0; - - private Loadable loadable; - private boolean quickMode = false; - - private final Reply draft = new Reply(); - private boolean shouldSaveDraft = true; - - private String captchaResponse; - - private int defaultTextColor; - private int maxCommentCount; - - // Views - private View container; - private ViewFlipper flipper; - private Button cancelButton; - private ImageButton fileButton; - private Button submitButton; - private EditText nameView; - private EditText emailView; - private EditText subjectView; - private EditText commentView; - private EditText fileNameView; - private CheckBox spoilerImageView; - private LoadView imageViewContainer; - private CaptchaLayout captchaLayout; - private LoadView responseContainer; - private Button insertSpoiler; - private Button insertCode; - private TextView commentCountView; - private TextView fileStatusView; - - private AppCompatActivity context; - - public static ReplyFragment newInstance(Loadable loadable, boolean quickMode) { - ReplyFragment reply = new ReplyFragment(); - reply.loadable = loadable; - reply.quickMode = quickMode; - return reply; - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - - loadable.writeToBundle(context, outState); - outState.putBoolean(context.getPackageName() + ".quickmode", quickMode); - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - context = (AppCompatActivity) getActivity(); - - if (loadable == null && savedInstanceState != null) { - loadable = new Loadable(); - loadable.readFromBundle(context, savedInstanceState); - quickMode = savedInstanceState.getBoolean(context.getPackageName() + ".quickmode"); - } - - if (loadable != null) { - setClosable(true); - - Dialog dialog = getDialog(); - String title = (loadable.isThreadMode() ? context.getString(R.string.reply_to_board) : context.getString(R.string.reply_to_board)) + " " + loadable.title; - - if (dialog == null) { - context.getSupportActionBar().setTitle(title); - } else { - dialog.setTitle(title); - // todo move elsewhere - dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); - dialog.setOnKeyListener(new Dialog.OnKeyListener() { - @Override - public boolean onKey(DialogInterface dialogInterface, int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_BACK) { - onBackPressed(); - return true; - } else - return false; - } - }); - } - - Reply draft = null; - - if (TextUtils.isEmpty(draft.name)) { - draft.name = ChanSettings.getDefaultName(); - } - - nameView.setText(draft.name); - emailView.setText(draft.options); - subjectView.setText(draft.subject); - commentView.setText(draft.comment); - commentView.setSelection(draft.selection); - - setFile(draft.fileName, draft.file); - spoilerImageView.setChecked(draft.spoilerImage); - - if (loadable.isThreadMode()) { - subjectView.setVisibility(View.GONE); - } - - if (quickMode) { - nameView.setVisibility(View.GONE); - emailView.setVisibility(View.GONE); - subjectView.setVisibility(View.GONE); - } - - defaultTextColor = commentView.getCurrentTextColor(); - - Board b = ChanApplication.getBoardManager().getBoardByValue(loadable.board); - if (b != null) { - insertSpoiler.setVisibility(b.spoilers ? View.VISIBLE : View.GONE); - insertCode.setVisibility(b.codeTags ? View.VISIBLE : View.GONE); - maxCommentCount = b.maxCommentChars; - } - - commentView.addTextChangedListener(new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - } - - @Override - public void afterTextChanged(Editable s) { - showCommentCount(); - } - }); - showCommentCount(); - - String baseUrl = loadable.isThreadMode() ? ChanUrls.getThreadUrlDesktop(loadable.board, loadable.no) : ChanUrls.getBoardUrlDesktop(loadable.board); - captchaLayout.initCaptcha(baseUrl, ChanUrls.getCaptchaSiteKey(), - ThemeHelper.getInstance().getTheme().isLightTheme, ChanApplication.getInstance().getUserAgent(), this); - } else { - Logger.e(TAG, "Loadable in ReplyFragment was null"); - closeReply(); - } - } - - @Override - public void onPause() { - super.onPause(); - - ReplyManager replyManager = ChanApplication.getReplyManager(); - - if (shouldSaveDraft) { - draft.name = nameView.getText().toString(); - draft.options = emailView.getText().toString(); - draft.subject = subjectView.getText().toString(); - draft.comment = commentView.getText().toString(); - draft.fileName = fileNameView.getText().toString(); - draft.spoilerImage = spoilerImageView.isChecked(); - draft.selection = commentView.getSelectionStart(); - -// replyManager.setReplyDraft(draft); - } else { -// replyManager.removeReplyDraft(); - setFile(null, null); - } - } - - @Override - public void onDestroy() { - super.onDestroy(); - - ReplyManager replyManager = ChanApplication.getReplyManager(); - replyManager.removeFileListener(); - - context = null; - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) { - // Setup the views with listeners - container = inflater.inflate(R.layout.reply_view, null); - flipper = (ViewFlipper) container.findViewById(R.id.reply_flipper); - - nameView = (EditText) container.findViewById(R.id.reply_name); - emailView = (EditText) container.findViewById(R.id.reply_email); - subjectView = (EditText) container.findViewById(R.id.reply_subject); - commentView = (EditText) container.findViewById(R.id.reply_comment); - commentView.requestFocus(); - fileNameView = (EditText) container.findViewById(R.id.reply_file_name); - spoilerImageView = (CheckBox) container.findViewById(R.id.reply_spoiler_image); - - imageViewContainer = (LoadView) container.findViewById(R.id.reply_image); - responseContainer = (LoadView) container.findViewById(R.id.reply_response); - captchaLayout = (CaptchaLayout) container.findViewById(R.id.captcha_layout); - - cancelButton = (Button) container.findViewById(R.id.reply_cancel); - cancelButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - if (page == 1) { - flipPage(0); - } else { - closeReply(); - } - } - }); - - fileButton = (ImageButton) container.findViewById(R.id.reply_file); - fileButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - if (draft.file == null) { - /*ChanApplication.getReplyManager().pickFile(new ReplyManager.FileListener() { - @Override - public void onFile(String name, File file) { - setFile(name, file); - } - - @Override - public void onFileLoading() { - imageViewContainer.setVisibility(View.VISIBLE); - imageViewContainer.setView(null); - } - });*/ - } else { - setFile(null, null); - } - } - }); - - submitButton = (Button) container.findViewById(R.id.reply_submit); - submitButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - if (page == 1 || ChanSettings.passLoggedIn()) { - flipPage(2); - submit(); - } else { - flipPage(1); - } - } - }); - - insertSpoiler = (Button) container.findViewById(R.id.insert_spoiler); - insertSpoiler.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - insertAtCursor("[spoiler]", "[/spoiler]"); - } - }); - - insertCode = (Button) container.findViewById(R.id.insert_code); - insertCode.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - insertAtCursor("[code]", "[/code]"); - } - }); - - commentCountView = (TextView) container.findViewById(R.id.reply_comment_counter); - - fileStatusView = (TextView) container.findViewById(R.id.reply_file_status); - - return container; - } - - public boolean onBackPressed() { - if (page == 1) { - flipPage(0); - return false; - } else { - return true; - } - } - - @Override - public void captchaLoaded(CaptchaLayout captchaLayout) { - } - - @Override - public void captchaEntered(CaptchaLayout captchaLayout, String response) { - captchaResponse = response; - if (page == 1) { - flipPage(2); - submit(); - } - } - - private void insertAtCursor(String before, String after) { - int pos = commentView.getSelectionStart(); - String text = commentView.getText().toString(); - text = new StringBuilder(text).insert(pos, before + after).toString(); - commentView.setText(text); - commentView.setSelection(pos + before.length()); - } - - private void showCommentCount() { - int count = commentView.getText().length(); - commentCountView.setText(count + "/" + maxCommentCount); - if (count > maxCommentCount) { - commentCountView.setTextColor(0xffff0000); - } else { - commentCountView.setTextColor(defaultTextColor); - } - } - - private void closeReply() { - if (getDialog() != null) { - dismissAllowingStateLoss(); - } else { - context.finish(); - } - } - - /** - * Set if the dialog is able to be closed, by pressing outside of the - * dialog, or something else. - */ - private void setClosable(boolean e) { - if (getDialog() != null) { - getDialog().setCanceledOnTouchOutside(e); - setCancelable(e); - } - } - - /** - * Flip to an page with an animation. Sets the correct text on the - * cancelButton: - * - * @param position 0-2 - */ - private void flipPage(int position) { - boolean flipBack = position < page; - - page = position; - - if (flipBack) { - flipper.setInAnimation(ViewFlipperAnimations.BACK_IN); - flipper.setOutAnimation(ViewFlipperAnimations.BACK_OUT); - } else { - flipper.setInAnimation(ViewFlipperAnimations.NEXT_IN); - flipper.setOutAnimation(ViewFlipperAnimations.NEXT_OUT); - } - flipper.setDisplayedChild(position); - - if (page == 0) { - cancelButton.setText(R.string.cancel); - } else if (page == 1) { - cancelButton.setText(R.string.back); - } else if (page == 2) { - cancelButton.setText(R.string.close); - } - - if (page == 1) { - captchaLayout.load(); - submitButton.setEnabled(captchaResponse != null); - } else if (page == 0) { - submitButton.setEnabled(true); - } - } - - /** - * Set the picked image in the imageView. Sets the file in the draft. Call - * null on the file to empty the imageView. - * - * @param name the filename - * @param file the file - */ - private void setFile(final String name, final File file) { - draft.file = file; - draft.fileName = name; - - if (file == null) { - fileButton.setImageResource(ThemeHelper.getInstance().getTheme().isLightTheme ? R.drawable.ic_action_attachment : R.drawable.ic_action_attachment_dark); - imageViewContainer.removeAllViews(); - imageViewContainer.setVisibility(View.GONE); - fileNameView.setText(""); - fileNameView.setVisibility(View.GONE); - spoilerImageView.setVisibility(View.GONE); - spoilerImageView.setChecked(false); - fileStatusView.setVisibility(View.GONE); - } else { - fileButton.setImageResource(ThemeHelper.getInstance().getTheme().isLightTheme ? R.drawable.ic_action_cancel : R.drawable.ic_action_cancel_dark); - fileNameView.setVisibility(View.VISIBLE); - fileNameView.setText(name); - - Board b = ChanApplication.getBoardManager().getBoardByValue(loadable.board); - spoilerImageView.setVisibility(b != null && b.spoilers ? View.VISIBLE : View.GONE); - - if (b != null) { - boolean probablyWebm = name.endsWith(".webm"); - int maxSize = probablyWebm ? b.maxWebmSize : b.maxFileSize; - if (file.length() > maxSize) { - String fileSize = AndroidUtils.getReadableFileSize((int) file.length(), false); - String maxSizeString = AndroidUtils.getReadableFileSize(maxSize, false); - String text = getString(probablyWebm ? R.string.reply_webm_too_big : R.string.reply_file_too_big, fileSize, maxSizeString); - fileStatusView.setVisibility(View.VISIBLE); - fileStatusView.setText(text); - } else { - fileStatusView.setVisibility(View.GONE); - } - } - - imageViewContainer.setVisibility(View.VISIBLE); - imageViewContainer.setView(null); - imageViewContainer.post(new Runnable() { - public void run() { - if (file.length() < 10 * 1024 * 1024) { - new Thread(new Runnable() { - @Override - public void run() { - if (context == null) - return; - - final Bitmap bitmap = ImageDecoder.decodeFile(file, imageViewContainer.getWidth(), imageViewContainer.getWidth()); - - context.runOnUiThread(new Runnable() { - @Override - public void run() { - if (context != null) { - if (bitmap != null) { - ImageView imageView = new ImageView(context); - imageViewContainer.setView(imageView); - imageView.setAdjustViewBounds(true); - imageView.setMaxWidth(imageViewContainer.getWidth()); - imageView.setMaxHeight(imageViewContainer.getWidth()); - imageView.setImageBitmap(bitmap); - } else { - noPreview(imageViewContainer); - } - } - } - }); - } - }).start(); - } else { - noPreview(imageViewContainer); - } - } - }); - } - } - - private void noPreview(LoadView loadView) { - TextView text = new TextView(context); - text.setLayoutParams(AndroidUtils.MATCH_WRAP_PARAMS); - text.setGravity(Gravity.CENTER); - text.setText(R.string.reply_no_preview); - text.setTextSize(16f); - int padding = dp(16); - text.setPadding(padding, padding, padding, padding); - loadView.setView(text); - } - - /** - * Submit button clicked at page 1 - */ - private void submit() { - submitButton.setEnabled(false); - cancelButton.setEnabled(false); - setClosable(false); - - responseContainer.setView(null); - - draft.name = nameView.getText().toString(); - draft.options = emailView.getText().toString(); - draft.subject = subjectView.getText().toString(); - draft.comment = commentView.getText().toString(); - draft.captchaResponse = captchaResponse; - - draft.fileName = "image"; - String n = fileNameView.getText().toString(); - if (!TextUtils.isEmpty(n)) { - draft.fileName = n; - } - - draft.resto = loadable.isThreadMode() ? loadable.no : -1; - draft.board = loadable.board; - - if (ChanSettings.getPassEnabled()) { - draft.usePass = true; - draft.passId = ChanSettings.getPassId(); - } - - Board b = ChanApplication.getBoardManager().getBoardByValue(loadable.board); - draft.spoilerImage = b != null && b.spoilers && spoilerImageView.isChecked(); - - ChanApplication.getReplyManager().postReply(draft, new ReplyManager.ReplyListener() { - @Override - public void onResponse(ReplyManager.ReplyResponse response) { - handleSubmitResponse(response); - } - }); - } - - /** - * Got response about or reply from ReplyManager - * - * @param response - */ - private void handleSubmitResponse(ReplyManager.ReplyResponse response) { - if (context == null) - return; - - if (response.isNetworkError || response.isUserError) { - int resId = R.string.reply_error; - Toast.makeText(context, resId, Toast.LENGTH_LONG).show(); - submitButton.setEnabled(true); - cancelButton.setEnabled(true); - setClosable(true); - captchaResponse = null; - if (ChanSettings.passLoggedIn()) { - flipPage(0); - } else { - flipPage(1); - captchaLayout.reset(); - } - } else if (response.isSuccessful) { - shouldSaveDraft = false; - Toast.makeText(context, R.string.reply_success, Toast.LENGTH_SHORT).show(); - - // Pin thread on successful post - if (ChanSettings.getPinOnPost() && loadable.isThreadMode()) { - ChanApplication.getWatchManager().addPin(loadable); - } - - closeReply(); - } else { - cancelButton.setEnabled(true); - setClosable(true); - - WebView webView = new WebView(context); - WebSettings settings = webView.getSettings(); - settings.setSupportZoom(true); - - webView.loadData(response.responseData, "text/html", null); - - responseContainer.setView(webView); - } - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/fragment/SettingsFragment.java b/Clover/app/src/main/java/org/floens/chan/ui/fragment/SettingsFragment.java deleted file mode 100644 index e80c6af3..00000000 --- a/Clover/app/src/main/java/org/floens/chan/ui/fragment/SettingsFragment.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Clover - 4chan browser https://github.com/Floens/Clover/ - * Copyright (C) 2014 Floens - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.floens.chan.ui.fragment; - -import android.content.Intent; -import android.content.pm.PackageManager.NameNotFoundException; -import android.os.Bundle; -import android.preference.ListPreference; -import android.preference.Preference; -import android.preference.Preference.OnPreferenceClickListener; -import android.preference.PreferenceFragment; -import android.preference.PreferenceGroup; -import android.view.View; -import android.widget.ListView; -import android.widget.Toast; - -import org.floens.chan.R; -import org.floens.chan.core.settings.ChanSettings; -import org.floens.chan.ui.activity.AboutActivity; -import org.floens.chan.ui.activity.BaseActivity; -import org.floens.chan.ui.activity.LicenseActivity; -import org.floens.chan.ui.activity.SettingsActivity; -import org.floens.chan.utils.ThemeHelper; - -public class SettingsFragment extends PreferenceFragment { - private int clickCount = 0; - private boolean argumentsRead = false; - - private Preference developerPreference; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - addPreferencesFromResource(R.xml.preference); - - Preference aboutLicences = findPreference("about_licenses"); - if (aboutLicences != null) { - aboutLicences.setOnPreferenceClickListener(new OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - startActivity(new Intent(getActivity(), AboutActivity.class)); - - return true; - } - }); - } - - Preference aboutLicence = findPreference("about_license"); - if (aboutLicence != null) { - aboutLicence.setOnPreferenceClickListener(new OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - startActivity(new Intent(getActivity(), LicenseActivity.class)); - - return true; - } - }); - } - - Preference aboutVersion = findPreference("about_version"); - if (aboutVersion != null) { - aboutVersion.setOnPreferenceClickListener(new OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - if (++clickCount >= 5) { - clickCount = 0; - - boolean enabled = !ChanSettings.getDeveloper(); - ChanSettings.setDeveloper(enabled); - updateDeveloperPreference(); - - Toast.makeText(getActivity(), (enabled ? "Enabled " : "Disabled ") + "developer options", - Toast.LENGTH_LONG).show(); - } - - return true; - } - }); - - String version = ""; - try { - version = getActivity().getPackageManager().getPackageInfo(getActivity().getPackageName(), 0).versionName; - } catch (NameNotFoundException e) { - e.printStackTrace(); - } - - aboutVersion.setTitle(R.string.app_name); - aboutVersion.setSummary(version); - } - - developerPreference = findPreference("about_developer"); - ((PreferenceGroup) findPreference("group_about")).removePreference(developerPreference); - updateDeveloperPreference(); - - final ListPreference theme = (ListPreference) findPreference("preference_theme"); - String currentValue = theme.getValue(); - if (currentValue == null) { - theme.setValue((String) theme.getEntryValues()[0]); - currentValue = theme.getValue(); - } - updateSummary(theme, currentValue); - - theme.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - updateSummary(theme, newValue.toString()); - - // Thanks! https://github.com/CyanogenMod/android_packages_apps_Calculator/blob/cm-10.2/src/com/android/calculator2/view/PreferencesFragment.java - if (!newValue.toString().equals(ThemeHelper.getInstance().getTheme().name)) { - Intent intent = new Intent(getActivity(), SettingsActivity.class); - - intent.putExtra("pos", getListView().getFirstVisiblePosition()); - View child = getListView().getChildAt(0); - intent.putExtra("off", child != null ? child.getTop() : 0); - - ((SettingsActivity) getActivity()).restart(intent); - } - - return true; - } - }); - - final ListPreference font = (ListPreference) findPreference("preference_font"); - String currentFontValue = font.getValue(); - if (currentFontValue == null) { - font.setValue((String) font.getEntryValues()[0]); - currentFontValue = font.getValue(); - } - updateSummary(font, currentFontValue); - - font.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - updateSummary(font, newValue.toString()); - BaseActivity.doRestartOnResume = true; - - return true; - } - }); - } - - public void onStart() { - super.onStart(); - - final Bundle args = getArguments(); - if (args != null && !argumentsRead) { - argumentsRead = true; - getListView().setSelectionFromTop(args.getInt("pos", 0), args.getInt("off", 0)); - } - } - - @Override - public void onResume() { - super.onResume(); - - final Preference watchPreference = findPreference("watch_settings"); - if (watchPreference != null) { - watchPreference.setSummary(ChanSettings.getWatchEnabled() ? R.string.watch_summary_enabled - : R.string.watch_summary_disabled); - } - - final Preference passPreference = findPreference("pass_settings"); - if (passPreference != null) { - passPreference.setSummary(ChanSettings.getPassEnabled() ? R.string.pass_summary_enabled - : R.string.pass_summary_disabled); - } - } - - private ListView getListView() { - return (ListView) getView().findViewById(android.R.id.list); - } - - private void updateDeveloperPreference() { - if (ChanSettings.getDeveloper()) { - ((PreferenceGroup) findPreference("group_about")).addPreference(developerPreference); - } else { - ((PreferenceGroup) findPreference("group_about")).removePreference(developerPreference); - } - } - - private void updateSummary(ListPreference list, String value) { - int index = list.findIndexOfValue(value); - list.setSummary(list.getEntries()[index]); - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/fragment/ThreadFragment.java b/Clover/app/src/main/java/org/floens/chan/ui/fragment/ThreadFragment.java deleted file mode 100644 index 810eab92..00000000 --- a/Clover/app/src/main/java/org/floens/chan/ui/fragment/ThreadFragment.java +++ /dev/null @@ -1,648 +0,0 @@ -/* - * Clover - 4chan browser https://github.com/Floens/Clover/ - * Copyright (C) 2014 Floens - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.floens.chan.ui.fragment; - -import android.app.Fragment; -import android.content.Context; -import android.os.Bundle; -import android.util.AttributeSet; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.view.inputmethod.EditorInfo; -import android.widget.AbsListView; -import android.widget.AbsListView.OnScrollListener; -import android.widget.Button; -import android.widget.GridView; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.ListView; -import android.widget.RelativeLayout; -import android.widget.SearchView; -import android.widget.TextView; - -import com.android.volley.NetworkError; -import com.android.volley.NoConnectionError; -import com.android.volley.ServerError; -import com.android.volley.VolleyError; - -import org.floens.chan.R; -import org.floens.chan.core.settings.ChanSettings; -import org.floens.chan.core.loader.ChanLoader; -import org.floens.chan.core.loader.EndOfLineException; -import org.floens.chan.core.manager.ThreadManager; -import org.floens.chan.core.model.ChanThread; -import org.floens.chan.core.model.Loadable; -import org.floens.chan.core.model.Post; -import org.floens.chan.ui.activity.BaseActivity; -import org.floens.chan.ui.activity.ImageViewActivity; -import org.floens.chan.ui.adapter.PostAdapter; -import org.floens.chan.ui.view.LoadView; -import org.floens.chan.utils.AndroidUtils; -import org.floens.chan.utils.ImageSaver; -import org.floens.chan.utils.ThemeHelper; - -import java.util.ArrayList; -import java.util.List; - -import javax.net.ssl.SSLException; - -import static org.floens.chan.utils.AndroidUtils.dp; -import static org.floens.chan.utils.AndroidUtils.setItemBackground; - -public class ThreadFragment extends Fragment implements ThreadManager.ThreadManagerListener, PostAdapter.PostAdapterCallback { - private ThreadManager threadManager; - private Loadable loadable; - - private PostAdapter postAdapter; - private LoadView container; - private AbsListView listView; - private ImageView skip; - private FilterView filterView; - - private SkipLogic skipLogic; - private int highlightedPost = -1; - private ThreadManager.ViewMode viewMode = ThreadManager.ViewMode.LIST; - private boolean isFiltering = false; - - public static ThreadFragment newInstance(BaseActivity activity) { - ThreadFragment fragment = new ThreadFragment(); - fragment.threadManager = new ThreadManager(activity, fragment); - - return fragment; - } - - public void bindLoadable(Loadable l) { - if (loadable != null) { - threadManager.unbindLoader(); - } - - setEmpty(); - - loadable = l; - threadManager.bindLoader(loadable); - } - - public void requestData() { - threadManager.requestData(); - } - - public void requestNextData() { - threadManager.requestNextData(); - } - - public void reload() { - setEmpty(); - - threadManager.requestData(); - } - - public void openReply() { - if (threadManager.hasLoader()) { - threadManager.openReply(true); - } - } - - public boolean hasLoader() { - return threadManager.hasLoader(); - } - - public void setViewMode(ThreadManager.ViewMode viewMode) { - this.viewMode = viewMode; - } - - public ChanLoader getLoader() { - return threadManager.getChanLoader(); - } - - public void startFiltering() { - if (filterView != null) { - isFiltering = true; - filterView.setVisibility(View.VISIBLE); - filterView.focusSearch(); - } - } - - public void highlightPost(int no) { - highlightedPost = no; - } - - @Override - public void onDestroy() { - super.onDestroy(); - - if (threadManager != null) { - threadManager.onDestroy(); - } - threadManager = null; - loadable = null; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setHasOptionsMenu(true); - } - - @Override - public void onStart() { - super.onStart(); - - if (threadManager != null) { - threadManager.onStart(); - } - } - - @Override - public void onStop() { - super.onStop(); - - if (threadManager != null) { - threadManager.onStop(); - } - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) { - container = new LoadView(inflater.getContext()); - if (loadable == null) { - container.setView(getCenteredMessageView(R.string.thread_not_specified)); - } - - return container; - } - - @Override - public void onPostClicked(Post post) { - if (loadable.isBoardMode() || loadable.isCatalogMode()) { - ((BaseActivity) getActivity()).onOPClicked(post); - } else if (loadable.isThreadMode() && isFiltering) { - filterView.clearSearch(); -// postAdapter.scrollToPost(post.no); - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (loadable.isThreadMode()) { - switch (item.getItemId()) { - case R.id.action_download_album: - // Get the posts with images - ArrayList imagePosts = new ArrayList<>(); -// for (Post post : postAdapter.getList()) { -// if (post.hasImage) { -// imagePosts.add(post); -// } -// } - if (imagePosts.size() > 0) { - List list = new ArrayList<>(); - - String folderName = Post.generateTitle(imagePosts.get(0), 10); - - String filename; - for (Post post : imagePosts) { - filename = (ChanSettings.getImageSaveOriginalFilename() ? post.tim : post.filename) + "." + post.ext; - list.add(new ImageSaver.DownloadPair(post.imageUrl, filename)); - } - - ImageSaver.getInstance().saveAll(getActivity(), folderName, list); - } - - return true; - } - } - - return super.onOptionsItemSelected(item); - } - - @Override - public void onThumbnailClicked(Post source) { - if (postAdapter != null) { - ImageViewActivity.launch(getActivity(), postAdapter, source.no, threadManager); - } - } - - @Override - public void onScrollTo(int post) { - if (postAdapter != null) { -// postAdapter.scrollToPost(post); - } - } - - @Override - public void onRefreshView() { - if (postAdapter != null) { - postAdapter.notifyDataSetChanged(); - } - } - - @Override - public void onOpenThread(final Loadable thread, int highlightedPost) { - ((BaseActivity) getActivity()).onOpenThread(thread); - this.highlightedPost = highlightedPost; - } - - @Override - public ThreadManager.ViewMode getViewMode() { - return viewMode; - } - - @Override - public void onThreadLoaded(ChanThread thread) { - if (postAdapter == null) { - if (container != null) { - container.setView(createView()); - } - } - -// postAdapter.setError(null); - postAdapter.setThread(thread); - - if (highlightedPost >= 0) { - threadManager.highlightPost(highlightedPost); -// postAdapter.scrollToPost(highlightedPost); - highlightedPost = -1; - } - - ((BaseActivity) getActivity()).onThreadLoaded(thread); - } - - @Override - public void onThreadLoadError(VolleyError error) { - if (error instanceof EndOfLineException) { -// postAdapter.setEndOfLine(true); - } else { - if (postAdapter == null) { - if (container != null) { - container.setView(getLoadErrorView(error)); - } - } else { -// postAdapter.setError(getLoadErrorText(error)); - } - } - - highlightedPost = -1; - } - - public void onFilteredResults(String filter, int count, boolean all) { - isFiltering = !all; - - if (filterView != null) { - filterView.setText(filter, count, all); - } - } - - @Override - public Loadable getLoadable() { - return loadable; - } - - @Override - public void onListScrolledToBottom() { - - } - - private RelativeLayout createView() { - RelativeLayout compound = new RelativeLayout(getActivity()); - - LinearLayout listViewContainer = new LinearLayout(getActivity()); - listViewContainer.setOrientation(LinearLayout.VERTICAL); - - filterView = new FilterView(getActivity()); - filterView.setVisibility(View.GONE); - listViewContainer.addView(filterView, AndroidUtils.MATCH_WRAP_PARAMS); - - if (viewMode == ThreadManager.ViewMode.LIST) { - ListView list = new ListView(getActivity()); - listView = list; -// postAdapter = new PostAdapter(getActivity(), threadManager, listView, this); -// listView.setAdapter(postAdapter); - list.setSelectionFromTop(loadable.listViewIndex, loadable.listViewTop); - } else if (viewMode == ThreadManager.ViewMode.GRID) { - GridView grid = new GridView(getActivity()); - grid.setNumColumns(GridView.AUTO_FIT); - int postGridWidth = getActivity().getResources().getDimensionPixelSize(R.dimen.post_grid_width); - grid.setColumnWidth(postGridWidth); - listView = grid; -// postAdapter = new PostAdapter(getActivity(), threadManager, listView, this); -// listView.setAdapter(postAdapter); - listView.setSelection(loadable.listViewIndex); - } - - listView.setOnScrollListener(new OnScrollListener() { - @Override - public void onScrollStateChanged(AbsListView view, int scrollState) { - if (!isFiltering) { - if (skipLogic != null) { - skipLogic.onScrollStateChanged(view, scrollState); - } - } - } - - @Override - public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { - if (!isFiltering) { - if (loadable != null) { - int index = view.getFirstVisiblePosition(); - View v = view.getChildAt(0); - int top = v == null ? 0 : v.getTop(); - if (index != 0 || top != 0) { - loadable.listViewIndex = index; - loadable.listViewTop = top; - } - } - if (skipLogic != null) { - skipLogic.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount); - } - } - } - }); - - listViewContainer.addView(listView, AndroidUtils.MATCH_PARAMS); - - compound.addView(listViewContainer, AndroidUtils.MATCH_PARAMS); - - if (loadable.isThreadMode()) { - skip = new ImageView(getActivity()); - skip.setImageResource(R.drawable.skip_arrow_down); - skip.setVisibility(View.GONE); - compound.addView(skip, AndroidUtils.WRAP_PARAMS); - - RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) skip.getLayoutParams(); - params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); - params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM); - params.setMargins(0, 0, dp(8), dp(8)); - skip.setLayoutParams(params); - - skipLogic = new SkipLogic(skip, listView); - } - - return compound; - } - - private void setEmpty() { - postAdapter = null; - - if (container != null) { - container.setView(null); - } - - if (listView != null) { - listView.setOnScrollListener(null); - listView = null; - } - - skip = null; - skipLogic = null; - filterView = null; - } - - private void doFilter(String filter) { - if (postAdapter != null) { -// postAdapter.setFilter(filter); - } - } - - /** - * Returns an TextView containing the appropriate error message - * - * @param error - * @return - */ - private View getLoadErrorView(VolleyError error) { - String errorMessage = getLoadErrorText(error); - - LinearLayout wrapper = new LinearLayout(getActivity()); - wrapper.setLayoutParams(AndroidUtils.MATCH_PARAMS); - wrapper.setGravity(Gravity.CENTER); - wrapper.setOrientation(LinearLayout.VERTICAL); - - TextView text = new TextView(getActivity()); - text.setLayoutParams(AndroidUtils.WRAP_PARAMS); - text.setText(errorMessage); - text.setTextSize(24f); - wrapper.addView(text); - - Button retry = new Button(getActivity()); - retry.setText(R.string.thread_load_failed_retry); - retry.setLayoutParams(AndroidUtils.WRAP_PARAMS); - retry.setGravity(Gravity.CENTER); - retry.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (threadManager != null) { - reload(); - } - } - }); - - wrapper.addView(retry); - - LinearLayout.LayoutParams retryParams = (LinearLayout.LayoutParams) retry.getLayoutParams(); - retryParams.topMargin = dp(12); - retry.setLayoutParams(retryParams); - - return wrapper; - } - - private String getLoadErrorText(VolleyError error) { - String errorMessage; - - if (error.getCause() instanceof SSLException) { - errorMessage = getString(R.string.thread_load_failed_ssl); - } else if ((error instanceof NoConnectionError) || (error instanceof NetworkError)) { - errorMessage = getString(R.string.thread_load_failed_network); - } else if (error instanceof ServerError) { - errorMessage = getString(R.string.thread_load_failed_server); - } else { - errorMessage = getString(R.string.thread_load_failed_parsing); - } - - return errorMessage; - } - - private View getCenteredMessageView(int stringResourceId) { - LinearLayout layout = new LinearLayout(getActivity()); - layout.setGravity(Gravity.CENTER); - TextView messageView = new TextView(getActivity()); - messageView.setText(getString(stringResourceId)); - layout.addView(messageView); - - return layout; - } - - private static class SkipLogic { - private final ImageView skip; - private int lastFirstVisibleItem; - private int lastTop; - private boolean up = false; - private final AbsListView listView; - - public SkipLogic(ImageView skipView, AbsListView list) { - skip = skipView; - listView = list; - skip.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (up) { - listView.setSelection(0); - } else { - listView.setSelection(listView.getCount() - 1); - } - skip.setVisibility(View.GONE); - } - }); - } - - public void onScrollStateChanged(AbsListView view, int scrollState) { - if (scrollState != AbsListView.OnScrollListener.SCROLL_STATE_IDLE) { - skip.setVisibility(View.VISIBLE); - } - } - - public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { - View v = view.getChildAt(0); - int top = (v == null) ? 0 : v.getTop(); - - if (firstVisibleItem == lastFirstVisibleItem) { - if (top > lastTop) { - onUp(); - } else if (top < lastTop) { - onDown(); - } - } else { - if (firstVisibleItem > lastFirstVisibleItem) { - onDown(); - } else { - onUp(); - } - } - lastFirstVisibleItem = firstVisibleItem; - lastTop = top; - } - - private void onUp() { - skip.setImageResource(R.drawable.skip_arrow_up); - up = true; - } - - private void onDown() { - skip.setImageResource(R.drawable.skip_arrow_down); - up = false; - } - } - - public class FilterView extends LinearLayout { - private SearchView searchView; - private TextView textView; - - public FilterView(Context activity) { - super(activity); - init(); - } - - public FilterView(Context activity, AttributeSet attr) { - super(activity, attr); - init(); - } - - public FilterView(Context activity, AttributeSet attr, int style) { - super(activity, attr, style); - init(); - } - - public void focusSearch() { - searchView.requestFocus(); - } - - public void clearSearch() { - searchView.setQuery("", false); - doFilter(""); - setVisibility(View.GONE); - } - - private void init() { - setOrientation(LinearLayout.VERTICAL); - - LinearLayout searchViewContainer = new LinearLayout(getContext()); - searchViewContainer.setOrientation(LinearLayout.HORIZONTAL); - - searchView = new SearchView(getContext()); - searchView.setIconifiedByDefault(false); - searchView.setImeOptions(EditorInfo.IME_FLAG_NO_FULLSCREEN); - searchViewContainer.addView(searchView); - LinearLayout.LayoutParams searchViewParams = (LinearLayout.LayoutParams) searchView.getLayoutParams(); - searchViewParams.weight = 1f; - searchViewParams.width = 0; - searchViewParams.height = LayoutParams.MATCH_PARENT; - searchView.setLayoutParams(searchViewParams); - - ImageView closeButton = new ImageView(getContext()); - searchViewContainer.addView(closeButton); - closeButton.setImageResource(ThemeHelper.getInstance().getTheme().isLightTheme ? R.drawable.ic_action_cancel : R.drawable.ic_action_cancel_dark); - LinearLayout.LayoutParams closeButtonParams = (LinearLayout.LayoutParams) closeButton.getLayoutParams(); - searchViewParams.width = dp(48); - searchViewParams.height = LayoutParams.MATCH_PARENT; - closeButton.setLayoutParams(closeButtonParams); - setItemBackground(closeButton); - int padding = dp(8); - closeButton.setPadding(padding, padding, padding, padding); - - closeButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - clearSearch(); - } - }); - - addView(searchViewContainer, new LayoutParams(LayoutParams.MATCH_PARENT, dp(48))); - - searchView.setQueryHint(getString(R.string.search_hint)); - searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { - @Override - public boolean onQueryTextSubmit(String query) { - doFilter(query); - return false; - } - - @Override - public boolean onQueryTextChange(String newText) { - doFilter(newText); - return false; - } - }); - - textView = new TextView(getContext()); - textView.setGravity(Gravity.CENTER); - addView(textView, new LayoutParams(LayoutParams.MATCH_PARENT, dp(28))); - } - - private void setText(String filter, int count, boolean all) { - if (all) { - textView.setText(""); - } else { -// String posts = getContext().getString(count == 1 ? R.string.one_post : R.string.multiple_posts); -// String text = getContext().getString(R.string.search_results, Integer.toString(count), posts, filter); -// textView.setText(text); - } - } - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/helper/PostHelper.java b/Clover/app/src/main/java/org/floens/chan/ui/helper/PostHelper.java index 26961bcd..1bff0825 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/helper/PostHelper.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/helper/PostHelper.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.helper; import android.content.res.Resources; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/helper/SwipeItemAnimator.java b/Clover/app/src/main/java/org/floens/chan/ui/helper/SwipeItemAnimator.java index 64a94ee4..6f7f6e79 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/helper/SwipeItemAnimator.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/helper/SwipeItemAnimator.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.helper; import android.support.v4.view.ViewCompat; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/helper/SwipeListener.java b/Clover/app/src/main/java/org/floens/chan/ui/helper/SwipeListener.java index ef7c7f28..96f698b3 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/helper/SwipeListener.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/helper/SwipeListener.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.helper; import android.content.Context; @@ -35,7 +52,6 @@ public class SwipeListener extends RecyclerView.ItemDecoration implements Recycl private final int flingPixels; private final int maxFlingPixels; - private final Context context; private Callback callback; private final RecyclerView recyclerView; private final LinearLayoutManager layoutManager; @@ -83,7 +99,6 @@ public class SwipeListener extends RecyclerView.ItemDecoration implements Recycl }; public SwipeListener(Context context, RecyclerView rv, Callback callback) { - this.context = context; recyclerView = rv; this.callback = callback; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/layout/ReplyLayout.java b/Clover/app/src/main/java/org/floens/chan/ui/layout/ReplyLayout.java index d7b7e388..9fbe21a3 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/layout/ReplyLayout.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/layout/ReplyLayout.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.layout; import android.content.Context; @@ -326,7 +343,7 @@ public class ReplyLayout extends LoadView implements View.OnClickListener, Anima @Override public void onFilePickError() { - Toast.makeText(getContext(), R.string.file_open_failed, Toast.LENGTH_LONG).show(); + Toast.makeText(getContext(), R.string.reply_file_open_failed, Toast.LENGTH_LONG).show(); } @Override diff --git a/Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadLayout.java b/Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadLayout.java index 3b6d6a49..4ebd5dde 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadLayout.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadLayout.java @@ -199,12 +199,12 @@ public class ThreadLayout extends LoadView implements ThreadPresenter.ThreadPres ClipboardManager clipboard = (ClipboardManager) AndroidUtils.getAppRes().getSystemService(Context.CLIPBOARD_SERVICE); ClipData clip = ClipData.newPlainText("Post text", post.comment.toString()); clipboard.setPrimaryClip(clip); - Toast.makeText(getContext(), R.string.post_text_copied_to_clipboard, Toast.LENGTH_SHORT).show(); + Toast.makeText(getContext(), R.string.post_text_copied, Toast.LENGTH_SHORT).show(); } @Override public void openLink(final String link) { - if (ChanSettings.getOpenLinkConfirmation()) { + if (ChanSettings.openLinkConfirmation.get()) { new AlertDialog.Builder(getContext()) .setNegativeButton(R.string.cancel, null) .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { @@ -223,7 +223,7 @@ public class ThreadLayout extends LoadView implements ThreadPresenter.ThreadPres @Override public void openWebView(String title, String link) { - AndroidUtils.openWebView((Activity)getContext(), title, link); + AndroidUtils.openWebView((Activity) getContext(), title, link); } @Override diff --git a/Clover/app/src/main/java/org/floens/chan/ui/service/WatchNotifier.java b/Clover/app/src/main/java/org/floens/chan/ui/service/WatchNotifier.java index 836d0ca0..20c5a9e8 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/service/WatchNotifier.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/service/WatchNotifier.java @@ -26,16 +26,14 @@ import android.content.Intent; import android.os.IBinder; import android.support.v4.app.NotificationCompat; -import org.floens.chan.ChanApplication; +import org.floens.chan.Chan; import org.floens.chan.R; -import org.floens.chan.core.settings.ChanSettings; import org.floens.chan.core.manager.WatchManager; import org.floens.chan.core.model.Pin; import org.floens.chan.core.model.Post; +import org.floens.chan.core.settings.ChanSettings; import org.floens.chan.core.watch.PinWatcher; import org.floens.chan.ui.activity.BoardActivity; -import org.floens.chan.ui.activity.ChanActivity; -import org.floens.chan.ui.activity.StartActivity; import org.floens.chan.utils.AndroidUtils; import java.util.ArrayList; @@ -61,7 +59,7 @@ public class WatchNotifier extends Service { super.onCreate(); nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - wm = ChanApplication.getWatchManager(); + wm = Chan.getWatchManager(); startForeground(NOTIFICATION_ID, createNotification()); } @@ -92,8 +90,8 @@ public class WatchNotifier extends Service { } private Notification createNotification() { - boolean notifyQuotesOnly = ChanSettings.getWatchNotifyMode().equals("quotes"); - boolean soundQuotesOnly = ChanSettings.getWatchSound().equals("quotes"); + boolean notifyQuotesOnly = ChanSettings.watchNotifyMode.get().equals("quotes"); + boolean soundQuotesOnly = ChanSettings.watchSound.get().equals("quotes"); List list = new ArrayList<>(); List listQuoting = new ArrayList<>(); @@ -138,7 +136,7 @@ public class WatchNotifier extends Service { } } - if (ChanApplication.getInstance().getApplicationInForeground()) { + if (Chan.getInstance().getApplicationInForeground()) { ticker = false; sound = false; } @@ -210,7 +208,6 @@ public class WatchNotifier extends Service { * @param expandedLines A list of lines for the big notification, or null if not shown * @param makeSound Should the notification make a sound * @param target The target pin, or null to open the pinned pane on tap - * @return */ @SuppressWarnings("deprecation") private Notification getNotificationFor(String tickerText, String contentTitle, String contentText, int contentNumber, @@ -231,7 +228,7 @@ public class WatchNotifier extends Service { } if (light) { - long watchLed = ChanSettings.getWatchLed(); + long watchLed = Long.parseLong(ChanSettings.watchLed.get(), 16); if (watchLed >= 0) { builder.setLights((int) watchLed, 1000, 1000); } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/settings/BooleanSettingView.java b/Clover/app/src/main/java/org/floens/chan/ui/settings/BooleanSettingView.java index bf9b180e..8612dd67 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/settings/BooleanSettingView.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/settings/BooleanSettingView.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.settings; import android.support.v7.widget.SwitchCompat; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/settings/LinkSettingView.java b/Clover/app/src/main/java/org/floens/chan/ui/settings/LinkSettingView.java index b0a4e1d6..5bdb0af8 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/settings/LinkSettingView.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/settings/LinkSettingView.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.settings; import android.view.View; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/settings/ListSettingView.java b/Clover/app/src/main/java/org/floens/chan/ui/settings/ListSettingView.java index 022b5cac..2a485ff0 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/settings/ListSettingView.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/settings/ListSettingView.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.settings; import android.view.Gravity; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/settings/SettingView.java b/Clover/app/src/main/java/org/floens/chan/ui/settings/SettingView.java index 5bb66e7f..9d4593de 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/settings/SettingView.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/settings/SettingView.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.settings; import android.view.View; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/settings/SettingsController.java b/Clover/app/src/main/java/org/floens/chan/ui/settings/SettingsController.java index d0ac8c34..3b525b2f 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/settings/SettingsController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/settings/SettingsController.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.settings; import android.content.Context; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/settings/SettingsGroup.java b/Clover/app/src/main/java/org/floens/chan/ui/settings/SettingsGroup.java index 10352e81..3a69a21c 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/settings/SettingsGroup.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/settings/SettingsGroup.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.settings; import java.util.ArrayList; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/settings/StringSettingView.java b/Clover/app/src/main/java/org/floens/chan/ui/settings/StringSettingView.java index 5edbb1b6..d94a740c 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/settings/StringSettingView.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/settings/StringSettingView.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.settings; import android.app.AlertDialog; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/toolbar/NavigationItem.java b/Clover/app/src/main/java/org/floens/chan/ui/toolbar/NavigationItem.java index 6255663e..1ecfc495 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/toolbar/NavigationItem.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/toolbar/NavigationItem.java @@ -20,9 +20,7 @@ package org.floens.chan.ui.toolbar; import android.content.Context; import android.view.View; import android.widget.LinearLayout; -import android.widget.TextView; -import org.floens.chan.R; import org.floens.chan.ui.view.FloatingMenu; import org.floens.chan.ui.view.FloatingMenuItem; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/toolbar/Toolbar.java b/Clover/app/src/main/java/org/floens/chan/ui/toolbar/Toolbar.java index 66780594..c606e906 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/toolbar/Toolbar.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/toolbar/Toolbar.java @@ -22,9 +22,9 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; +import android.annotation.SuppressLint; import android.content.Context; import android.graphics.drawable.Drawable; -import android.os.Build; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; @@ -54,7 +54,7 @@ import java.util.List; import static org.floens.chan.utils.AndroidUtils.dp; import static org.floens.chan.utils.AndroidUtils.getAttrColor; -import static org.floens.chan.utils.AndroidUtils.getAttrDrawable; +import static org.floens.chan.utils.AndroidUtils.setRoundItemBackground; public class Toolbar extends LinearLayout implements View.OnClickListener, LoadView.Listener { private ImageView arrowMenuView; @@ -150,11 +150,7 @@ public class Toolbar extends LinearLayout implements View.OnClickListener, LoadV arrowMenuDrawable = new ArrowMenuDrawable(); arrowMenuView.setImageDrawable(arrowMenuDrawable); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - arrowMenuView.setBackground(getAttrDrawable(getContext(), android.R.attr.selectableItemBackgroundBorderless)); - } else { - arrowMenuView.setBackgroundResource(R.drawable.item_background); - } + setRoundItemBackground(arrowMenuView); leftButtonContainer.addView(arrowMenuView, new FrameLayout.LayoutParams(dp(56), FrameLayout.LayoutParams.MATCH_PARENT, Gravity.CENTER_VERTICAL)); @@ -352,6 +348,7 @@ public class Toolbar extends LinearLayout implements View.OnClickListener, LoadV return searchViewWrapper; } else { + @SuppressLint("InflateParams") LinearLayout menu = (LinearLayout) LayoutInflater.from(getContext()).inflate(R.layout.toolbar_menu, null); menu.setGravity(Gravity.CENTER_VERTICAL); diff --git a/Clover/app/src/main/java/org/floens/chan/ui/toolbar/ToolbarMenu.java b/Clover/app/src/main/java/org/floens/chan/ui/toolbar/ToolbarMenu.java index 75778ba9..fb74a947 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/toolbar/ToolbarMenu.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/toolbar/ToolbarMenu.java @@ -64,7 +64,7 @@ public class ToolbarMenu extends LinearLayout { } public ToolbarMenuItem createOverflow(ToolbarMenuItem.ToolbarMenuItemCallback callback) { - ToolbarMenuItem overflow = addItem(new ToolbarMenuItem(getContext(), callback, 100, 100, R.drawable.ic_more)); + ToolbarMenuItem overflow = addItem(new ToolbarMenuItem(getContext(), callback, 100, 100, R.drawable.ic_more_vert_white_24dp)); ImageView overflowImage = overflow.getView(); overflowImage.setLayoutParams(new LinearLayout.LayoutParams(dp(36), dp(54))); overflowImage.setPadding(0, 0, dp(16), 0); diff --git a/Clover/app/src/main/java/org/floens/chan/ui/toolbar/ToolbarMenuItem.java b/Clover/app/src/main/java/org/floens/chan/ui/toolbar/ToolbarMenuItem.java index 361f6bd5..a85fb303 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/toolbar/ToolbarMenuItem.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/toolbar/ToolbarMenuItem.java @@ -19,17 +19,15 @@ package org.floens.chan.ui.toolbar; import android.content.Context; import android.graphics.drawable.Drawable; -import android.os.Build; import android.view.View; import android.widget.ImageView; import android.widget.LinearLayout; -import org.floens.chan.R; import org.floens.chan.ui.view.FloatingMenu; import org.floens.chan.ui.view.FloatingMenuItem; import static org.floens.chan.utils.AndroidUtils.dp; -import static org.floens.chan.utils.AndroidUtils.getAttrDrawable; +import static org.floens.chan.utils.AndroidUtils.setRoundItemBackground; public class ToolbarMenuItem implements View.OnClickListener, FloatingMenu.FloatingMenuCallback { private ToolbarMenuItemCallback callback; @@ -63,11 +61,7 @@ public class ToolbarMenuItem implements View.OnClickListener, FloatingMenu.Float imageView.setImageDrawable(drawable); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - imageView.setBackground(getAttrDrawable(context, android.R.attr.selectableItemBackgroundBorderless)); - } else { - imageView.setBackgroundResource(R.drawable.item_background); - } + setRoundItemBackground(imageView); } } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/transition/ImageTransition.java b/Clover/app/src/main/java/org/floens/chan/ui/transition/ImageTransition.java deleted file mode 100644 index e92fd6aa..00000000 --- a/Clover/app/src/main/java/org/floens/chan/ui/transition/ImageTransition.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.floens.chan.ui.transition; - -import org.floens.chan.controller.ControllerTransition; - -public class ImageTransition extends ControllerTransition { - @Override - public void perform() { - - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/view/CrossfadeView.java b/Clover/app/src/main/java/org/floens/chan/ui/view/CrossfadeView.java index e1465362..72d03af5 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/view/CrossfadeView.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/view/CrossfadeView.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.view; import android.animation.Animator; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/view/CustomNetworkImageView.java b/Clover/app/src/main/java/org/floens/chan/ui/view/CustomNetworkImageView.java deleted file mode 100644 index 224f96cb..00000000 --- a/Clover/app/src/main/java/org/floens/chan/ui/view/CustomNetworkImageView.java +++ /dev/null @@ -1,296 +0,0 @@ -/** - * Copyright (C) 2013 The Android Open Source Project - * - * 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 org.floens.chan.ui.view; - -import android.content.Context; -import android.text.TextUtils; -import android.util.AttributeSet; -import android.view.ViewGroup.LayoutParams; -import android.widget.ImageView; - -import com.android.volley.VolleyError; -import com.android.volley.toolbox.ImageLoader; -import com.android.volley.toolbox.ImageLoader.ImageContainer; -import com.android.volley.toolbox.ImageLoader.ImageListener; - -/** - * Custom version of NetworkImageView - *

- * Handles fetching an image from a URL as well as the life-cycle of the - * associated request. - */ -public class CustomNetworkImageView extends ImageView { - /** - * The URL of the network image to load - */ - private String mUrl; - - /** - * Resource ID of the image to be used as a placeholder until the network - * image is loaded. - */ - private int mDefaultImageId; - - /** - * Resource ID of the image to be used if the network response fails. - */ - private int mErrorImageId; - - /** - * Local copy of the ImageLoader. - */ - private ImageLoader mImageLoader; - - /** - * Current ImageContainer. (either in-flight or finished) - */ - private ImageContainer mImageContainer; - - /** - * Max amount to scale the image inside the view - */ - private float mMaxScale = 1; - - private int mFadeTime; - - private int mForcedWidth = -1; - private int mForcedHeight = -1; - - public CustomNetworkImageView(Context context) { - this(context, null); - } - - public CustomNetworkImageView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public CustomNetworkImageView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - /** - * How larger the inner bitmap is to the defined view size. - * - * @param amount - */ - public void setMaxScale(float amount) { - mMaxScale = amount; - } - - public float getMaxScale() { - return mMaxScale; - } - - public void forceImageDimensions(int w, int h) { - mForcedWidth = w; - mForcedHeight = h; - } - - public String getUrl() { - return mUrl; - } - - /** - * Animate the image fading in. - * - * @param time duration of the fade animation in milliseconds - */ - public void setFadeIn(int time) { - mFadeTime = time; - } - - /** - * Sets URL of the image that should be loaded into this view. Note that - * calling this will immediately either set the cached image (if available) - * or the default image specified by - * {@link CustomNetworkImageView#setDefaultImageResId(int)} on the view. - *

- * NOTE: If applicable, - * {@link CustomNetworkImageView#setDefaultImageResId(int)} and - * {@link CustomNetworkImageView#setErrorImageResId(int)} should be called - * prior to calling this function. - * - * @param url The URL that should be loaded into this ImageView. - * @param imageLoader ImageLoader that will be used to make the request. - */ - public void setImageUrl(String url, ImageLoader imageLoader) { - mUrl = url; - mImageLoader = imageLoader; - // The URL has potentially changed. See if we need to load it. - loadImageIfNecessary(false); - } - - /** - * Sets the default image resource ID to be used for this view until the - * attempt to load it completes. - */ - public void setDefaultImageResId(int defaultImage) { - mDefaultImageId = defaultImage; - } - - /** - * Sets the error image resource ID to be used for this view in the event - * that the image requested fails to load. - */ - public void setErrorImageResId(int errorImage) { - mErrorImageId = errorImage; - } - - public void onErrorResponse(VolleyError error) { - } - - /** - * Loads the image for the view if it isn't already loaded. - * - * @param isInLayoutPass True if this was invoked from a layout pass, false otherwise. - */ - void loadImageIfNecessary(final boolean isInLayoutPass) { - int width; - int height; - boolean wrapWidth = false, wrapHeight = false; - - if (mForcedWidth < 0 || mForcedHeight < 0) { - width = getWidth(); - height = getHeight(); - - if (getLayoutParams() != null) { - wrapWidth = getLayoutParams().width == LayoutParams.WRAP_CONTENT; - wrapHeight = getLayoutParams().height == LayoutParams.WRAP_CONTENT; - } - - // if the view's bounds aren't known yet, and this is not a - // wrap-content/wrap-content - // view, hold off on loading the image. - boolean isFullyWrapContent = wrapWidth && wrapHeight; - if (width == 0 && height == 0 && !isFullyWrapContent) { - return; - } - } else { - width = mForcedWidth; - height = mForcedHeight; - } - - // if the URL to be loaded in this view is empty, cancel any old - // requests and clear the - // currently loaded image. - if (TextUtils.isEmpty(mUrl)) { - if (mImageContainer != null) { - mImageContainer.cancelRequest(); - mImageContainer = null; - } - setDefaultImageOrNull(); - return; - } - - // if there was an old request in this view, check if it needs to be - // canceled. - if (mImageContainer != null && mImageContainer.getRequestUrl() != null) { - if (mImageContainer.getRequestUrl().equals(mUrl)) { - // if the request is from the same URL, return. - return; - } else { - // if there is a pre-existing request, cancel it if it's - // fetching a different URL. - mImageContainer.cancelRequest(); - setDefaultImageOrNull(); - } - } - - // Calculate the max image width / height to use while ignoring - // WRAP_CONTENT dimens. - int maxWidth = wrapWidth ? 0 : width; - int maxHeight = wrapHeight ? 0 : height; - - // The pre-existing content of this view didn't match the current URL. - // Load the new image - // from the network. - ImageContainer newContainer = mImageLoader.get(mUrl, new ImageListener() { - @Override - public void onErrorResponse(VolleyError error) { - if (mErrorImageId != 0) { - setImageResource(mErrorImageId); - } - - CustomNetworkImageView.this.onErrorResponse(error); - } - - @Override - public void onResponse(final ImageContainer response, boolean isImmediate) { - // If this was an immediate response that was delivered inside of a layout - // pass do not set the image immediately as it will trigger a requestLayout - // inside of a layout. Instead, defer setting the image by posting back to - // the main thread. - if (isImmediate && isInLayoutPass) { - post(new Runnable() { - @Override - public void run() { - onResponse(response, false); - } - }); - return; - } - - if (response.getBitmap() != null) { - setImageBitmap(response.getBitmap()); - - if (mFadeTime > 0 && !isImmediate) { - setAlpha(0f); - animate().alpha(1f).setDuration(mFadeTime); - } - } else if (mDefaultImageId != 0) { - setImageResource(mDefaultImageId); - } - } - }, (int) (maxWidth * mMaxScale), (int) (maxHeight * mMaxScale)); - - // update the ImageContainer to be the new bitmap container. - mImageContainer = newContainer; - } - - private void setDefaultImageOrNull() { - if (mDefaultImageId != 0) { - setImageResource(mDefaultImageId); - } else { - setImageBitmap(null); - } - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - super.onLayout(changed, left, top, right, bottom); - loadImageIfNecessary(true); - } - - @Override - protected void onDetachedFromWindow() { - if (mImageContainer != null) { - // If the view was bound to an image request, cancel it and clear - // out the image from the view. - mImageContainer.cancelRequest(); - setImageBitmap(null); - // also clear out the container so we can reload the image if - // necessary. - mImageContainer = null; - } - super.onDetachedFromWindow(); - } - - @Override - protected void drawableStateChanged() { - super.drawableStateChanged(); - invalidate(); - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/view/CustomScaleImageView.java b/Clover/app/src/main/java/org/floens/chan/ui/view/CustomScaleImageView.java index c9e02cf7..51ab9e81 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/view/CustomScaleImageView.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/view/CustomScaleImageView.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.view; import android.content.Context; @@ -71,6 +88,7 @@ public class CustomScaleImageView extends SubsamplingScaleImageView { public interface Callback { void onReady(); + void onError(boolean wasInitial); } } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/view/DragGripView.java b/Clover/app/src/main/java/org/floens/chan/ui/view/DragGripView.java deleted file mode 100644 index 41660c5e..00000000 --- a/Clover/app/src/main/java/org/floens/chan/ui/view/DragGripView.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2013 Google Inc. - * - * 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 org.floens.chan.ui.view; - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.RectF; -import android.util.AttributeSet; -import android.util.DisplayMetrics; -import android.util.TypedValue; -import android.view.Gravity; -import android.view.View; - -public class DragGripView extends View { - private static final int[] ATTRS = new int[]{ - android.R.attr.gravity, - android.R.attr.color, - }; - - private static final int HORIZ_RIDGES = 2; - - private int mGravity = Gravity.START; - private int mColor = 0xff666666; - - private final Paint mRidgePaint; - private final RectF mTempRectF = new RectF(); - - private final float mRidgeSize; - private final float mRidgeGap; - - // private int mWidth; - private int mHeight; - - public DragGripView(Context context) { - this(context, null, 0); - } - - public DragGripView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public DragGripView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - final TypedArray a = context.obtainStyledAttributes(attrs, ATTRS); - mGravity = a.getInteger(0, mGravity); - mColor = a.getColor(1, mColor); - a.recycle(); - - final DisplayMetrics res = getResources().getDisplayMetrics(); - mRidgeSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4, res); - mRidgeGap = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, res); - - mRidgePaint = new Paint(); - mRidgePaint.setColor(mColor); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - setMeasuredDimension( - View.resolveSize( - (int) (HORIZ_RIDGES * (mRidgeSize + mRidgeGap) - mRidgeGap) - + getPaddingLeft() + getPaddingRight(), - widthMeasureSpec - ), - View.resolveSize( - (int) mRidgeSize, - heightMeasureSpec) - ); - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - -// float drawWidth = HORIZ_RIDGES * (mRidgeSize + mRidgeGap) - mRidgeGap; - float drawLeft = getPaddingLeft(); - - int vertRidges = (int) ((mHeight - getPaddingTop() - getPaddingBottom() + mRidgeGap) - / (mRidgeSize + mRidgeGap)); - float drawHeight = vertRidges * (mRidgeSize + mRidgeGap) - mRidgeGap; - float drawTop = getPaddingTop() - + ((mHeight - getPaddingTop() - getPaddingBottom()) - drawHeight) / 2; - - for (int y = 0; y < vertRidges; y++) { - for (int x = 0; x < HORIZ_RIDGES; x++) { - mTempRectF.set( - drawLeft + x * (mRidgeSize + mRidgeGap), - drawTop + y * (mRidgeSize + mRidgeGap), - drawLeft + x * (mRidgeSize + mRidgeGap) + mRidgeSize, - drawTop + y * (mRidgeSize + mRidgeGap) + mRidgeSize); - canvas.drawOval(mTempRectF, mRidgePaint); - } - } - } - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - mHeight = h; -// mWidth = w; - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/view/FloatingMenu.java b/Clover/app/src/main/java/org/floens/chan/ui/view/FloatingMenu.java index 13393927..c3105fdd 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/view/FloatingMenu.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/view/FloatingMenu.java @@ -34,7 +34,6 @@ import org.floens.chan.R; import org.floens.chan.utils.AndroidUtils; import org.floens.chan.utils.Logger; -import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/view/HackyViewPager.java b/Clover/app/src/main/java/org/floens/chan/ui/view/HackyViewPager.java deleted file mode 100644 index 71b870e1..00000000 --- a/Clover/app/src/main/java/org/floens/chan/ui/view/HackyViewPager.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Clover - 4chan browser https://github.com/Floens/Clover/ - * Copyright (C) 2014 Floens - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.floens.chan.ui.view; - -import android.content.Context; -import android.support.v4.view.ViewPager; -import android.util.AttributeSet; -import android.view.MotionEvent; - -/** - * Hacky fix for Issue #4 and - * http://code.google.com/p/android/issues/detail?id=18990 - *

- * ScaleGestureDetector seems to mess up the touch events, which means that - * ViewGroups which make use of onInterceptTouchEvent throw a lot of - * IllegalArgumentException: pointerIndex out of range. - *

- * There's not much I can do in my code for now, but we can mask the result by - * just catching the problem and ignoring it. - * - * @author Chris Banes - */ -public class HackyViewPager extends ViewPager { - - public HackyViewPager(Context context) { - super(context); - } - - public HackyViewPager(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - try { - return super.onInterceptTouchEvent(ev); - } catch (IllegalArgumentException e) { - e.printStackTrace(); - return false; - } - } - -} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/view/LoadingBar.java b/Clover/app/src/main/java/org/floens/chan/ui/view/LoadingBar.java index a3af7010..471e5bda 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/view/LoadingBar.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/view/LoadingBar.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.view; import android.content.Context; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/view/MultiImageView.java b/Clover/app/src/main/java/org/floens/chan/ui/view/MultiImageView.java index aa26bf96..e1dcc1d3 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/view/MultiImageView.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/view/MultiImageView.java @@ -25,7 +25,6 @@ import android.net.Uri; import android.util.AttributeSet; import android.view.Gravity; import android.view.View; -import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.MediaController; @@ -36,12 +35,12 @@ import com.android.volley.VolleyError; import com.android.volley.toolbox.ImageLoader.ImageContainer; import com.davemorrissey.labs.subscaleview.ImageSource; -import org.floens.chan.ChanApplication; +import org.floens.chan.Chan; import org.floens.chan.R; +import org.floens.chan.core.cache.FileCache; import org.floens.chan.core.model.PostImage; import org.floens.chan.core.settings.ChanSettings; import org.floens.chan.utils.AndroidUtils; -import org.floens.chan.utils.FileCache; import org.floens.chan.utils.Logger; import java.io.File; @@ -161,7 +160,7 @@ public class MultiImageView extends FrameLayout implements View.OnClickListener } // Also use volley for the thumbnails - thumbnailRequest = ChanApplication.getVolleyImageLoader().get(thumbnailUrl, new com.android.volley.toolbox.ImageLoader.ImageListener() { + thumbnailRequest = Chan.getVolleyImageLoader().get(thumbnailUrl, new com.android.volley.toolbox.ImageLoader.ImageListener() { @Override public void onErrorResponse(VolleyError error) { thumbnailRequest = null; @@ -188,7 +187,7 @@ public class MultiImageView extends FrameLayout implements View.OnClickListener } callback.showProgress(this, true); - bigImageRequest = ChanApplication.getFileCache().downloadFile(imageUrl, new FileCache.DownloadedCallback() { + bigImageRequest = Chan.getFileCache().downloadFile(imageUrl, new FileCache.DownloadedCallback() { @Override public void onProgress(long downloaded, long total, boolean done) { callback.onProgress(MultiImageView.this, downloaded, total); @@ -245,7 +244,7 @@ public class MultiImageView extends FrameLayout implements View.OnClickListener } callback.showProgress(this, true); - gifRequest = ChanApplication.getFileCache().downloadFile(gifUrl, new FileCache.DownloadedCallback() { + gifRequest = Chan.getFileCache().downloadFile(gifUrl, new FileCache.DownloadedCallback() { @Override public void onProgress(long downloaded, long total, boolean done) { callback.onProgress(MultiImageView.this, downloaded, total); @@ -296,7 +295,7 @@ public class MultiImageView extends FrameLayout implements View.OnClickListener public void setVideo(String videoUrl) { callback.showProgress(this, true); - videoRequest = ChanApplication.getFileCache().downloadFile(videoUrl, new FileCache.DownloadedCallback() { + videoRequest = Chan.getFileCache().downloadFile(videoUrl, new FileCache.DownloadedCallback() { @Override public void onProgress(long downloaded, long total, boolean done) { callback.onProgress(MultiImageView.this, downloaded, total); @@ -326,7 +325,7 @@ public class MultiImageView extends FrameLayout implements View.OnClickListener } public void setVideoFile(final File file) { - if (ChanSettings.getVideoExternal()) { + if (ChanSettings.videoOpenExternal.get()) { Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(file), "video/*"); diff --git a/Clover/app/src/main/java/org/floens/chan/ui/view/OptionalSwipeViewPager.java b/Clover/app/src/main/java/org/floens/chan/ui/view/OptionalSwipeViewPager.java index ded4fde1..24a5009c 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/view/OptionalSwipeViewPager.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/view/OptionalSwipeViewPager.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.view; import android.content.Context; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/view/PostView.java b/Clover/app/src/main/java/org/floens/chan/ui/view/PostView.java deleted file mode 100644 index 88f62311..00000000 --- a/Clover/app/src/main/java/org/floens/chan/ui/view/PostView.java +++ /dev/null @@ -1,633 +0,0 @@ -/* - * Clover - 4chan browser https://github.com/Floens/Clover/ - * Copyright (C) 2014 Floens - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.floens.chan.ui.view; - -import android.app.Activity; -import android.content.Context; -import android.content.res.TypedArray; -import android.text.Layout; -import android.text.Spannable; -import android.text.SpannableString; -import android.text.SpannedString; -import android.text.TextUtils; -import android.text.format.DateUtils; -import android.text.method.LinkMovementMethod; -import android.text.style.AbsoluteSizeSpan; -import android.text.style.BackgroundColorSpan; -import android.text.style.ClickableSpan; -import android.text.style.ForegroundColorSpan; -import android.util.AttributeSet; -import android.util.TypedValue; -import android.view.Menu; -import android.view.MenuItem; -import android.view.MotionEvent; -import android.view.View; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.PopupMenu; -import android.widget.RelativeLayout; -import android.widget.TextView; - -import com.android.volley.toolbox.NetworkImageView; - -import org.floens.chan.ChanApplication; -import org.floens.chan.R; -import org.floens.chan.core.model.Loadable; -import org.floens.chan.core.model.Post; -import org.floens.chan.core.model.PostLinkable; -import org.floens.chan.utils.IconCache; -import org.floens.chan.utils.ThemeHelper; -import org.floens.chan.utils.Time; - -import static org.floens.chan.utils.AndroidUtils.setItemBackground; - -public class PostView extends LinearLayout implements View.OnClickListener, PostLinkable.Callback { - private final static LinearLayout.LayoutParams matchParams = new LinearLayout.LayoutParams( - LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); - private final static LinearLayout.LayoutParams wrapParams = new LinearLayout.LayoutParams( - LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); - private final static LinearLayout.LayoutParams matchWrapParams = new LinearLayout.LayoutParams( - LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); - private final static LinearLayout.LayoutParams wrapMatchParams = new LinearLayout.LayoutParams( - LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); - - private final Activity context; - - private Post post; - private PostViewCallback callback; - private Loadable loadable; - private int highlightQuotesNo = -1; - - private boolean ignoreNextOnClick = false; - - private boolean isBuild = false; - private LinearLayout full; - private LinearLayout contentContainer; - private int imageSize; - private ThumbnailView thumbnailView; - private TextView titleView; - private TextView commentView; - private TextView repliesCountView; - private LinearLayout iconsView; - private ImageView stickyView; - private ImageView closedView; - private ImageView deletedView; - private ImageView archivedView; - private NetworkImageView countryView; - private ImageView optionsView; - private View lastSeen; - - /** - * Represents a post. Use setPost(Post ThreadManager) to fill it with data. - * setPost can be called multiple times (useful for ListView). - * - * @param activity - */ - public PostView(Context activity) { - super(activity); - context = (Activity) activity; - } - - public PostView(Context activity, AttributeSet attbs) { - super(activity, attbs); - context = (Activity) activity; - } - - public PostView(Context activity, AttributeSet attbs, int style) { - super(activity, attbs, style); - context = (Activity) activity; - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - if (this.post != null) { - setPostLinkableListener(null); - } - } - - public void setPost(final Post post, final PostViewCallback callback, boolean highlighted) { - if (this.post != null) { - // Remove callbacks from the old post while it is still set - setPostLinkableListener(null); - } - - this.post = post; - this.callback = callback; - this.loadable = callback.getLoadable(); - - highlightQuotesNo = -1; - setPostLinkableListener(this); - - boolean boardCatalogMode = loadable.isBoardMode() || loadable.isCatalogMode(); - - TypedArray ta = context.obtainStyledAttributes(null, R.styleable.PostView, R.attr.post_style, 0); - - if (!isBuild) { - buildView(context, ta); - isBuild = true; - } - - int dateColor = ta.getColor(R.styleable.PostView_date_color, 0); - int savedReplyColor = ta.getColor(R.styleable.PostView_saved_reply_color, 0); - int highlightedColor = ta.getColor(R.styleable.PostView_highlighted_color, 0); - int detailSize = ta.getDimensionPixelSize(R.styleable.PostView_detail_size, 0); - - ta.recycle(); - - if (post.hasImage) { - thumbnailView.setVisibility(View.VISIBLE); - thumbnailView.setUrl(post.thumbnailUrl, imageSize, imageSize); - } else { - thumbnailView.setVisibility(View.GONE); - thumbnailView.setUrl(null, 0, 0); - } - - CharSequence total = new SpannableString(""); - - if (post.subjectSpan != null) { - total = TextUtils.concat(total, post.subjectSpan); - } - - if (isList()) { - CharSequence relativeTime = DateUtils.getRelativeTimeSpanString(post.time * 1000L, Time.get(), DateUtils.SECOND_IN_MILLIS, 0); - SpannableString date = new SpannableString("No." + post.no + " " + relativeTime); - date.setSpan(new ForegroundColorSpan(dateColor), 0, date.length(), 0); - date.setSpan(new AbsoluteSizeSpan(detailSize), 0, date.length(), 0); - - total = TextUtils.concat(total, post.subjectSpan == null ? "" : "\n", post.nameTripcodeIdCapcodeSpan, date, " "); - } - - if (!TextUtils.isEmpty(total)) { - titleView.setText(total); - titleView.setVisibility(View.VISIBLE); - } else { - titleView.setVisibility(View.GONE); - } - - commentView.setText(post.comment); - - if (loadable.isThreadMode()) { - commentView.setMovementMethod(new PostViewMovementMethod()); - commentView.setOnClickListener(this); - } else { - commentView.setOnClickListener(null); - commentView.setClickable(false); - commentView.setMovementMethod(null); - } - - if (isGrid() || ((post.isOP && boardCatalogMode && post.replies > 0) || (post.repliesFrom.size() > 0))) { - repliesCountView.setVisibility(View.VISIBLE); - - String text = ""; - - int count = boardCatalogMode ? post.replies : post.repliesFrom.size(); - - if (count != 1) { - text = count + " " + context.getString(R.string.multiple_replies); - } else if (count == 1) { - text = count + " " + context.getString(R.string.one_reply); - } - - if (boardCatalogMode && post.images > 0) { - if (post.images != 1) { - text += ", " + post.images + " " + context.getString(R.string.multiple_images); - } else { - text += ", " + post.images + " " + context.getString(R.string.one_image); - } - } - - if (loadable.isThreadMode()) { - repliesCountView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - callback.onShowPostReplies(post); - } - }); - } - - repliesCountView.setText(text); - } else { - repliesCountView.setVisibility(View.GONE); - repliesCountView.setOnClickListener(null); - } - - boolean showCountryFlag = isList() && !TextUtils.isEmpty(post.country) && !TextUtils.isEmpty(post.countryUrl); - boolean showStickyIcon = isList() && post.sticky; - boolean showDeletedIcon = isList() && post.deleted; - boolean showArchivedIcon = isList() && post.archived; - boolean showClosedIcon = isList() && post.closed && !showArchivedIcon; - - iconsView.setVisibility((showCountryFlag || showStickyIcon || showClosedIcon || showDeletedIcon || showArchivedIcon) ? View.VISIBLE : View.GONE); - - stickyView.setVisibility(showStickyIcon ? View.VISIBLE : View.GONE); - closedView.setVisibility(showClosedIcon ? View.VISIBLE : View.GONE); - deletedView.setVisibility(showDeletedIcon ? View.VISIBLE : View.GONE); - archivedView.setVisibility(showArchivedIcon ? View.VISIBLE : View.GONE); - if (showCountryFlag) { - countryView.setVisibility(View.VISIBLE); - countryView.setImageUrl(post.countryUrl, ChanApplication.getVolleyImageLoader()); - } else { - countryView.setVisibility(View.GONE); - countryView.setImageUrl(null, null); - } - - if (post.isSavedReply) { - full.setBackgroundColor(savedReplyColor); - } else if (highlighted) { - full.setBackgroundColor(highlightedColor); - } else { - full.setBackgroundColor(0x00000000); - } - - if (callback.isPostLastSeen(post)) { - lastSeen.setVisibility(View.VISIBLE); - } else { - lastSeen.setVisibility(View.GONE); - } - } - - public Post getPost() { - return post; - } - - public ThumbnailView getThumbnail() { - return thumbnailView; - } - - public void setHighlightQuotesWithNo(int no) { - highlightQuotesNo = no; - } - - private void setPostLinkableListener(PostLinkable.Callback callback) { - if (post.comment instanceof SpannedString) { - SpannedString commentSpannable = (SpannedString) post.comment; - PostLinkable[] linkables = commentSpannable.getSpans(0, commentSpannable.length(), PostLinkable.class); - for (PostLinkable linkable : linkables) { - if (callback == null) { - if (linkable.hasCallback(this)) { - linkable.removeCallback(this); - } - } else { - linkable.addCallback(callback); - } - } - } - } - - private void buildView(final Context context, TypedArray ta) { - int thumbnailBackground = ta.getColor(R.styleable.PostView_thumbnail_background, 0); - int replyCountColor = ta.getColor(R.styleable.PostView_reply_count_color, 0); - - int iconPadding = ta.getDimensionPixelSize(R.styleable.PostView_icon_padding, 0); - int iconWidth = ta.getDimensionPixelSize(R.styleable.PostView_icon_width, 0); - int iconHeight = ta.getDimensionPixelSize(R.styleable.PostView_icon_height, 0); - int gridHeight = ta.getDimensionPixelSize(R.styleable.PostView_grid_height, 0); - int optionsSpacing = ta.getDimensionPixelSize(R.styleable.PostView_options_spacing, 0); - int titleSize = ta.getDimensionPixelSize(R.styleable.PostView_title_size, 0); - int optionsLeftPadding = ta.getDimensionPixelSize(R.styleable.PostView_options_left_padding, 0); - int optionsTopPadding = ta.getDimensionPixelSize(R.styleable.PostView_options_top_padding, 0); - int optionsRightPadding = ta.getDimensionPixelSize(R.styleable.PostView_options_right_padding, 0); - int optionsBottomPadding = ta.getDimensionPixelSize(R.styleable.PostView_options_bottom_padding, 0); - int lastSeenHeight = ta.getDimensionPixelSize(R.styleable.PostView_last_seen_height, 0); - - int postListMaxHeight = ta.getDimensionPixelSize(R.styleable.PostView_list_comment_max_height, 0); - - int postCommentSize = 0; - int commentPadding = 0; - int postPadding = 0; - imageSize = 0; - int repliesCountSize = 0; - if (isList()) { - postCommentSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 12, getResources().getDisplayMetrics()); - commentPadding = ta.getDimensionPixelSize(R.styleable.PostView_list_comment_padding, 0); - postPadding = ta.getDimensionPixelSize(R.styleable.PostView_list_padding, 0); - imageSize = ta.getDimensionPixelSize(R.styleable.PostView_list_image_size, 0); - repliesCountSize = ta.getDimensionPixelSize(R.styleable.PostView_list_replies_count_size, 0); - } else if (isGrid()) { - postCommentSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 12 - 1, getResources().getDisplayMetrics()); - commentPadding = ta.getDimensionPixelSize(R.styleable.PostView_grid_comment_padding, 0); - postPadding = ta.getDimensionPixelSize(R.styleable.PostView_grid_padding, 0); - imageSize = ta.getDimensionPixelSize(R.styleable.PostView_grid_image_size, 0); - repliesCountSize = ta.getDimensionPixelSize(R.styleable.PostView_grid_replies_count_size, 0); - } - - RelativeLayout wrapper = new RelativeLayout(context); - wrapper.setLayoutParams(matchParams); - - full = new LinearLayout(context); - if (isList()) { - full.setOrientation(HORIZONTAL); - wrapper.addView(full, matchParams); - } else if (isGrid()) { - full.setOrientation(VERTICAL); - wrapper.addView(full, new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, gridHeight)); - } - - LinearLayout imageContainer = new LinearLayout(context); - imageContainer.setOrientation(VERTICAL); - imageContainer.setBackgroundColor(thumbnailBackground); - - // Create thumbnail - thumbnailView = new ThumbnailView(context); - thumbnailView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - callback.onThumbnailClicked(post, thumbnailView); - } - }); - - if (isList()) { - imageContainer.addView(thumbnailView, new LinearLayout.LayoutParams(imageSize, imageSize)); - full.addView(imageContainer, wrapMatchParams); - full.setMinimumHeight(imageSize); - } else if (isGrid()) { - imageContainer.addView(thumbnailView, new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, imageSize)); - full.addView(imageContainer, matchWrapParams); - } - - contentContainer = new LinearLayout(context); - contentContainer.setOrientation(VERTICAL); - - LinearLayout titleContainer = new LinearLayout(context); - titleContainer.setOrientation(HORIZONTAL); - - if (isList()) { - // 25 padding to give optionsView some space - titleContainer.setPadding(0, 0, optionsSpacing, 0); - } - - titleView = new TextView(context); - titleView.setTextSize(TypedValue.COMPLEX_UNIT_PX, titleSize); - titleView.setPadding(postPadding, postPadding, postPadding, 0); - - titleContainer.addView(titleView, wrapParams); - - contentContainer.addView(titleContainer, matchWrapParams); - - iconsView = new LinearLayout(context); - iconsView.setOrientation(HORIZONTAL); - iconsView.setPadding(postPadding, iconPadding, postPadding, 0); - - stickyView = new ImageView(context); - stickyView.setImageDrawable(IconCache.stickyIcon); - iconsView.addView(stickyView, new LinearLayout.LayoutParams(iconWidth, iconHeight)); - - closedView = new ImageView(context); - closedView.setImageDrawable(IconCache.closedIcon); - iconsView.addView(closedView, new LinearLayout.LayoutParams(iconWidth, iconHeight)); - - deletedView = new ImageView(context); - deletedView.setImageDrawable(IconCache.trashIcon); - iconsView.addView(deletedView, new LinearLayout.LayoutParams(iconWidth, iconHeight)); - - archivedView = new ImageView(context); - archivedView.setImageDrawable(IconCache.archivedIcon); - iconsView.addView(archivedView, new LinearLayout.LayoutParams(iconWidth, iconHeight)); - - countryView = new NetworkImageView(context); - countryView.setScaleType(ImageView.ScaleType.FIT_CENTER); - iconsView.addView(countryView, new LinearLayout.LayoutParams(iconWidth, iconHeight)); - - contentContainer.addView(iconsView, matchWrapParams); - - commentView = new TextView(context); - commentView.setTextSize(TypedValue.COMPLEX_UNIT_PX, postCommentSize); - - if (isList()) { - commentView.setPadding(postPadding, commentPadding, postPadding, commentPadding); - - if (loadable.isBoardMode() || loadable.isCatalogMode()) { - commentView.setMaxHeight(postListMaxHeight); - } - } else if (isGrid()) { - commentView.setPadding(postPadding, commentPadding, postPadding, 0); - // So that is fills up all the height using weight later on - commentView.setMinHeight(10000); - } - - if (isList()) { - contentContainer.addView(commentView, matchWrapParams); - } else if (isGrid()) { - contentContainer.addView(commentView, new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, 0, 1f)); - } - - repliesCountView = new TextView(context); - setItemBackground(repliesCountView); - repliesCountView.setTextColor(replyCountColor); - repliesCountView.setPadding(postPadding, postPadding, postPadding, postPadding); - repliesCountView.setTextSize(TypedValue.COMPLEX_UNIT_PX, repliesCountSize); - repliesCountView.setSingleLine(); - - contentContainer.addView(repliesCountView, wrapParams); - - lastSeen = new View(context); - lastSeen.setBackgroundColor(0xffff0000); - contentContainer.addView(lastSeen, new LayoutParams(LayoutParams.MATCH_PARENT, lastSeenHeight)); - - if (!loadable.isThreadMode()) { - setItemBackground(contentContainer); - } - - full.addView(contentContainer, matchWrapParams); - - optionsView = new ImageView(context); - optionsView.setImageResource(R.drawable.ic_overflow); - setItemBackground(optionsView); - optionsView.setPadding(optionsLeftPadding, optionsTopPadding, optionsRightPadding, optionsBottomPadding); - optionsView.setOnClickListener(new OnClickListener() { - @Override - public void onClick(final View v) { - PopupMenu popupMenu = new PopupMenu(context, v); - callback.onPopulatePostOptions(post, popupMenu.getMenu()); - popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { - @Override - public boolean onMenuItemClick(MenuItem item) { - callback.onPostOptionClicked(post, item.getItemId()); - return true; - } - }); - popupMenu.show(); - if (ThemeHelper.getInstance().getTheme().isLightTheme) { - optionsView.setImageResource(R.drawable.ic_overflow_black); - popupMenu.setOnDismissListener(new PopupMenu.OnDismissListener() { - @Override - public void onDismiss(final PopupMenu menu) { - optionsView.setImageResource(R.drawable.ic_overflow); - } - }); - } - } - }); - wrapper.addView(optionsView, wrapParams); - RelativeLayout.LayoutParams optionsParams = (RelativeLayout.LayoutParams) optionsView.getLayoutParams(); - optionsParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); - optionsParams.addRule(RelativeLayout.ALIGN_PARENT_TOP); - optionsView.setLayoutParams(optionsParams); - - addView(wrapper, matchParams); - - wrapper.setOnClickListener(this); - } - - public void setOnClickListeners(final View.OnClickListener listener) { - commentView.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (ignoreNextOnClick) { - ignoreNextOnClick = false; - } else { - listener.onClick(v); - } - } - }); - } - - public void onLinkableClick(PostLinkable linkable) { - callback.onPostLinkableClicked(linkable); - } - - @Override - public int getMarkedNo(PostLinkable postLinkable) { - return highlightQuotesNo; - } - - @Override - public void onClick(View v) { - if (ignoreNextOnClick) { - ignoreNextOnClick = false; - } else { - callback.onPostClicked(post); - } - } - - private boolean isList() { - return true; - // TODO -// return callback.getViewMode() == ThreadManager.ViewMode.LIST; - } - - private boolean isGrid() { - return false; - // TODO -// return callback.getViewMode() == ThreadManager.ViewMode.GRID; - } - - public interface PostViewCallback { - Loadable getLoadable(); - - void onPostClicked(Post post); - - void onThumbnailClicked(Post post, ThumbnailView thumbnail); - - void onShowPostReplies(Post post); - - void onPopulatePostOptions(Post post, Menu menu); - - void onPostOptionClicked(Post post, int id); - - void onPostLinkableClicked(PostLinkable linkable); - - boolean isPostLastSeen(Post post); - } - - private static BackgroundColorSpan BACKGROUND_SPAN = new BackgroundColorSpan(0x6633B5E5); - - private class PostViewMovementMethod extends LinkMovementMethod { - @Override - public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) { - int action = event.getActionMasked(); - - if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_DOWN) { - int x = (int) event.getX(); - int y = (int) event.getY(); - - x -= widget.getTotalPaddingLeft(); - y -= widget.getTotalPaddingTop(); - - x += widget.getScrollX(); - y += widget.getScrollY(); - - Layout layout = widget.getLayout(); - int line = layout.getLineForVertical(y); - int off = layout.getOffsetForHorizontal(line, x); - - ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); - - if (link.length != 0) { - if (action == MotionEvent.ACTION_UP) { - ignoreNextOnClick = true; - link[0].onClick(widget); - buffer.removeSpan(BACKGROUND_SPAN); - } else if (action == MotionEvent.ACTION_DOWN) { - buffer.setSpan(BACKGROUND_SPAN, buffer.getSpanStart(link[0]), buffer.getSpanEnd(link[0]), 0); - } else if (action == MotionEvent.ACTION_CANCEL) { - buffer.removeSpan(BACKGROUND_SPAN); - } - - return true; - } else { - buffer.removeSpan(BACKGROUND_SPAN); - } - } - - return true; - } - } - - /*private class PostViewMovementMethod extends LinkMovementMethod { - @Override - public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) { - int action = event.getAction(); - - if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) { - int x = (int) event.getX(); - int y = (int) event.getY(); - - x -= widget.getTotalPaddingLeft(); - y -= widget.getTotalPaddingTop(); - - x += widget.getScrollX(); - y += widget.getScrollY(); - - Layout layout = widget.getLayout(); - int line = layout.getLineForVertical(y); - int off = layout.getOffsetForHorizontal(line, x); - - ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); - - if (link.length != 0) { - if (action == MotionEvent.ACTION_UP) { - link[0].onClick(widget); - } - - commentView.invalidate(); - - return true; - } else { - // Changed this to propagate events - PostView.this.onTouchEvent(event); - return true; - } - } else { - PostView.this.onTouchEvent(event); - return true; - } - } - }*/ -} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/view/SelectionListeningEditText.java b/Clover/app/src/main/java/org/floens/chan/ui/view/SelectionListeningEditText.java index 6bbb3a7b..7aa28973 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/view/SelectionListeningEditText.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/view/SelectionListeningEditText.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.view; import android.content.Context; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/view/ThumbnailView.java b/Clover/app/src/main/java/org/floens/chan/ui/view/ThumbnailView.java index f73ddeb4..35b80c46 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/view/ThumbnailView.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/view/ThumbnailView.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.view; import android.content.Context; @@ -18,7 +35,7 @@ import com.android.volley.NoConnectionError; import com.android.volley.VolleyError; import com.android.volley.toolbox.ImageLoader; -import org.floens.chan.ChanApplication; +import org.floens.chan.Chan; import org.floens.chan.R; import static org.floens.chan.utils.AndroidUtils.getString; @@ -78,7 +95,7 @@ public class ThumbnailView extends View implements ImageLoader.ImageListener { } if (!TextUtils.isEmpty(url)) { - container = ChanApplication.getVolleyImageLoader().get(url, this, width, height); + container = Chan.getVolleyImageLoader().get(url, this, width, height); } } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/view/TouchBlockingFrameLayout.java b/Clover/app/src/main/java/org/floens/chan/ui/view/TouchBlockingFrameLayout.java index da899715..5f08bacb 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/view/TouchBlockingFrameLayout.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/view/TouchBlockingFrameLayout.java @@ -1,6 +1,24 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.view; import android.content.Context; +import android.support.annotation.NonNull; import android.util.AttributeSet; import android.view.MotionEvent; import android.widget.FrameLayout; @@ -19,7 +37,7 @@ public class TouchBlockingFrameLayout extends FrameLayout { } @Override - public boolean onTouchEvent(MotionEvent event) { + public boolean onTouchEvent(@NonNull MotionEvent event) { return true; } } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/view/TransitionImageView.java b/Clover/app/src/main/java/org/floens/chan/ui/view/TransitionImageView.java index f32eaee8..090a7bf0 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/view/TransitionImageView.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/view/TransitionImageView.java @@ -1,3 +1,20 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.view; import android.content.Context; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/view/ViewPagerAdapter.java b/Clover/app/src/main/java/org/floens/chan/ui/view/ViewPagerAdapter.java index 2575f617..4318d76c 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/view/ViewPagerAdapter.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/view/ViewPagerAdapter.java @@ -1,11 +1,26 @@ +/* + * Clover - 4chan browser https://github.com/Floens/Clover/ + * Copyright (C) 2014 Floens + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package org.floens.chan.ui.view; import android.support.v4.view.PagerAdapter; import android.view.View; import android.view.ViewGroup; -import org.floens.chan.utils.AndroidUtils; - public abstract class ViewPagerAdapter extends PagerAdapter { @Override public Object instantiateItem(ViewGroup container, int position) { @@ -18,7 +33,7 @@ public abstract class ViewPagerAdapter extends PagerAdapter { @Override public void destroyItem(ViewGroup container, int position, Object object) { - container.removeView((View)object); + container.removeView((View) object); } public boolean isViewFromObject(View view, Object object) { diff --git a/Clover/app/src/main/java/org/floens/chan/utils/AndroidUtils.java b/Clover/app/src/main/java/org/floens/chan/utils/AndroidUtils.java index 82f0e231..5271c584 100644 --- a/Clover/app/src/main/java/org/floens/chan/utils/AndroidUtils.java +++ b/Clover/app/src/main/java/org/floens/chan/utils/AndroidUtils.java @@ -18,6 +18,7 @@ package org.floens.chan.utils; import android.annotation.SuppressLint; +import android.annotation.TargetApi; import android.app.Activity; import android.app.Dialog; import android.content.Context; @@ -41,22 +42,15 @@ import android.view.inputmethod.InputMethodManager; import android.webkit.WebView; import android.widget.Toast; -import org.floens.chan.ChanApplication; +import org.floens.chan.Chan; import org.floens.chan.R; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Locale; public class AndroidUtils { - public final static ViewGroup.LayoutParams MATCH_PARAMS = new ViewGroup.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); - public final static ViewGroup.LayoutParams WRAP_PARAMS = new ViewGroup.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); - public final static ViewGroup.LayoutParams MATCH_WRAP_PARAMS = new ViewGroup.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); - public final static ViewGroup.LayoutParams WRAP_MATCH_PARAMS = new ViewGroup.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT); private static HashMap typefaceCache = new HashMap<>(); public static Typeface ROBOTO_MEDIUM; @@ -68,11 +62,11 @@ public class AndroidUtils { } public static Resources getRes() { - return ChanApplication.con.getResources(); + return Chan.con.getResources(); } public static Context getAppRes() { - return ChanApplication.con; + return Chan.con; } public static String getString(int res) { @@ -80,13 +74,13 @@ public class AndroidUtils { } public static SharedPreferences getPreferences() { - return PreferenceManager.getDefaultSharedPreferences(ChanApplication.con); + return PreferenceManager.getDefaultSharedPreferences(Chan.con); } @SuppressLint("SetJavaScriptEnabled") public static void openWebView(Activity activity, String title, String link) { Dialog dialog = new Dialog(activity); - dialog.setContentView(R.layout.web_dialog); + dialog.setContentView(R.layout.dialog_web); WebView wb = (WebView) dialog.findViewById(R.id.web_view); wb.getSettings().setJavaScriptEnabled(true); wb.loadUrl(link); @@ -162,8 +156,6 @@ public class AndroidUtils { /** * Causes the runnable to be added to the message queue. The runnable will * be run on the ui thread. - * - * @param runnable */ public static void runOnUiThread(Runnable runnable) { new Handler(Looper.getMainLooper()).post(runnable); @@ -199,7 +191,7 @@ public class AndroidUtils { return bytes + " B"; int exp = (int) (Math.log(bytes) / Math.log(unit)); String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1) + (si ? "" : "i"); - return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre); + return String.format(Locale.US, "%.1f %sB", bytes / Math.pow(unit, exp), pre); } public static CharSequence ellipsize(CharSequence text, int max) { @@ -256,13 +248,9 @@ public class AndroidUtils { } } - public static void setItemBackground(View view) { - view.setBackgroundResource(R.drawable.item_background); - } - public static void setRoundItemBackground(View view) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - view.setBackground(getAttrDrawable(view.getContext(), android.R.attr.selectableItemBackgroundBorderless)); + setRoundItemBackgroundLollipop(view); } else { view.setBackgroundResource(R.drawable.item_background); } @@ -293,4 +281,9 @@ public class AndroidUtils { return false; } } + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + private static void setRoundItemBackgroundLollipop(View view) { + view.setBackground(getAttrDrawable(view.getContext(), android.R.attr.selectableItemBackgroundBorderless)); + } } diff --git a/Clover/app/src/main/java/org/floens/chan/utils/IconCache.java b/Clover/app/src/main/java/org/floens/chan/utils/IconCache.java deleted file mode 100644 index a59a46ad..00000000 --- a/Clover/app/src/main/java/org/floens/chan/utils/IconCache.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Clover - 4chan browser https://github.com/Floens/Clover/ - * Copyright (C) 2014 Floens - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.floens.chan.utils; - -import android.content.Context; -import android.content.res.Resources; -import android.graphics.BitmapFactory; -import android.graphics.drawable.BitmapDrawable; - -import org.floens.chan.R; - -public class IconCache { - public static BitmapDrawable stickyIcon; - public static BitmapDrawable closedIcon; - public static BitmapDrawable trashIcon; - public static BitmapDrawable archivedIcon; - - public static void createIcons(final Context context) { - Resources res = context.getResources(); - stickyIcon = new BitmapDrawable(res, BitmapFactory.decodeResource(res, R.drawable.sticky_icon)); - closedIcon = new BitmapDrawable(res, BitmapFactory.decodeResource(res, R.drawable.closed_icon)); - trashIcon = new BitmapDrawable(res, BitmapFactory.decodeResource(res, R.drawable.trash_icon)); - archivedIcon = new BitmapDrawable(res, BitmapFactory.decodeResource(res, R.drawable.archived_icon)); - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/utils/ImageSaver.java b/Clover/app/src/main/java/org/floens/chan/utils/ImageSaver.java index 940a29b1..ea361bb7 100644 --- a/Clover/app/src/main/java/org/floens/chan/utils/ImageSaver.java +++ b/Clover/app/src/main/java/org/floens/chan/utils/ImageSaver.java @@ -28,8 +28,9 @@ import android.media.MediaScannerConnection; import android.net.Uri; import android.widget.Toast; -import org.floens.chan.ChanApplication; +import org.floens.chan.Chan; import org.floens.chan.R; +import org.floens.chan.core.cache.FileCache; import org.floens.chan.core.settings.ChanSettings; import java.io.File; @@ -53,9 +54,9 @@ public class ImageSaver { private BroadcastReceiver receiver; public void saveAll(final Context context, String folderName, final List list) { - final File subFolder = new File(ChanSettings.getImageSaveDirectory() + File.separator + filterName(folderName)); + final File subFolder = new File(ChanSettings.saveLocation.get() + File.separator + filterName(folderName)); - String text = context.getString(R.string.download_confirm, Integer.toString(list.size()), subFolder.getAbsolutePath()); + String text = context.getString(R.string.image_download_confirm, Integer.toString(list.size()), subFolder.getAbsolutePath()); new AlertDialog.Builder(context).setMessage(text).setNegativeButton(R.string.cancel, null) .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { @@ -67,7 +68,7 @@ public class ImageSaver { } public void saveImage(final Context context, String imageUrl, final String name, final String extension, final boolean share) { - ChanApplication.getFileCache().downloadFile(imageUrl, new FileCache.DownloadedCallback() { + Chan.getFileCache().downloadFile(imageUrl, new FileCache.DownloadedCallback() { @Override @SuppressWarnings("deprecation") public void onProgress(long downloaded, long total, boolean done) { @@ -97,7 +98,7 @@ public class ImageSaver { new Thread(new Runnable() { @Override public void run() { - File saveDir = ChanSettings.getImageSaveDirectory(); + File saveDir = new File(ChanSettings.saveLocation.get()); if (!saveDir.isDirectory() && !saveDir.mkdirs()) { showToast(context, context.getString(R.string.image_save_directory_error)); diff --git a/Clover/app/src/main/java/org/floens/chan/utils/ThemeHelper.java b/Clover/app/src/main/java/org/floens/chan/utils/ThemeHelper.java index 99ccbb15..e69227f8 100644 --- a/Clover/app/src/main/java/org/floens/chan/utils/ThemeHelper.java +++ b/Clover/app/src/main/java/org/floens/chan/utils/ThemeHelper.java @@ -26,15 +26,15 @@ import org.floens.chan.core.settings.ChanSettings; public class ThemeHelper { public enum Theme { - LIGHT("light", R.style.AppTheme, true), - DARK("dark", R.style.AppTheme_Dark, false), - BLACK("black", R.style.AppTheme_Dark_Black, false); + LIGHT("light", R.style.Chan_Theme, true), + DARK("dark", R.style.Chan_Theme_Dark, false), + BLACK("black", R.style.Chan_Theme_Black, false); public String name; public int resValue; public boolean isLightTheme; - private Theme(String name, int resValue, boolean isLightTheme) { + Theme(String name, int resValue, boolean isLightTheme) { this.name = name; this.resValue = resValue; this.isLightTheme = isLightTheme; @@ -65,7 +65,7 @@ public class ThemeHelper { } public Theme getTheme() { - String themeName = ChanSettings.getTheme(); + String themeName = ChanSettings.theme.get(); Theme theme = null; switch (themeName) { diff --git a/Clover/app/src/main/res/drawable-hdpi/ic_action_attachment.png b/Clover/app/src/main/res/drawable-hdpi/ic_action_attachment.png deleted file mode 100644 index 175adeb4c46628209078396ccacbd4d1b2485f11..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 509 zcmVO87>ZXr=q1ZddatBhAHAVG@@{$WVZguIXSpO+OKXx?vYLL0b9 zBQ0eDn;P&)XVdD_fi}=vcUT93wyicsz@}J*wmWrY{BQA+roBxB_GEx5R(DsSBiruE z9SeH%j(qS)MijQ&Xrgu>p^V&B6P)le)RWOh_riI9 zffH|0GvPoE`Lyx@$%Y6!^vA zRbZhTulA&p$st+G4I9#RbR3xaKPG_**KSm#)V6HAyiF=~c3!{f3}s;IOqQbWE@Za3 zU59;;d0A@AKpC-a>g`Tl8E^DFI$!CS3}|P81)_Tt>hi&U-eBCaBOhi?Md;8rssyhO zHp&$yt%T?lef5E59XgQ{p=tJ)!vuyt3kyC;P2RzEVkKQCVozdIGOs^0_4qDxcB?GB zhSfb>CAJ7u^=Aj1Oypyzb%~_u5P_`CqPE^O|A7!f2qAYB9Dd`$Re@cH@UwGnffkSo-$Xz%e6@gd_$mQ}@Wlcs;fn;2 z!e6>iAVqd002ovPDHLkV1i#FjE?{S diff --git a/Clover/app/src/main/res/drawable-hdpi/ic_action_back_dark.png b/Clover/app/src/main/res/drawable-hdpi/ic_action_back_dark.png deleted file mode 100644 index 6bb7a0b061abac0a78af841c3306ff270ca5d83f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 296 zcmV+@0oVSCP)1kobz)zBFlf)!!^P@ zzMiDnqbLADelMU)!QuW2QT&K0{zfTYWE7(W#V|)PPE#ysD3+8Ii+YM}m6j2=4s+}F u;rQpHKGcL*b92`_BBs0$LWnSY1sDMQ)T=Bp-p}m-0000uR$+`ZL}CL9iu4pv&~TPqL?R?{{9XWYPqIRgeD^;8#3vi0QmIrbmFkC- z=lNP%LWrBV*rEMwV3MsoHqsVpnjWjFdZ5h9V<&ATapw~E1PAb=v+=Jp6hzH@=Ksnh z?p@-Z`}Cg%jQ{`u07*qoM6N<$g0AVdX8-^I diff --git a/Clover/app/src/main/res/drawable-hdpi/ic_action_cancel_dark.png b/Clover/app/src/main/res/drawable-hdpi/ic_action_cancel_dark.png deleted file mode 100644 index e206f296c2535b11a2243ae93a31b2957f42ab7d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 353 zcmV-n0iOPeP)l3^w)^1&PVosU-?Y zsp*+{wo31J?^jaDOtDo8H}y5}EpSfF$n>ZxN)4{^3rViZPPR-@vbR&PsjvbXkegbP zs8ErclUHn2VXFi-*9yo63F|8hm3bwJ6}oxF$}kgLQj3#|G7CyF^YauyCMG83 zmzLNn0bL65LT&-v*t}wBFaZNhzap_f-%!s00+w{G(#^lGsVi#&Ct}+$imdr$-u?X(ACh=#L&{!#L3yw z&D7A`#K{n**Cju>G&eP`1g19yq1OzjUQlAlEdbi=l3J8mmYU*Ll%J~r_Ow+d7PlC? zn3-5OIXVK(v%u~ah~5<3ZZW~>7JZ;&^g&UJ6xA>xVEO?u;RzSWfhYacJYae+0w(OB zPunsW7#L@Hx;TbZ+F}XRH$BVJ_~tbB>ux&w{i&Jpl6k3-y`NvKHk21q zV1%GG?pIzqOj6l*_t-(U9qjp;vo`HwN=}ep)5vUa_N7?Rr}hN4ng+Fwoh&_BpW+wD z&uL8OV?3O|erD1ih8>LjGWVRk>cn-L{3q>ay)F~Cc;}xn`8m#J@(k z@^-_wj*fK>KI!`&dhL6Y6 diff --git a/Clover/app/src/main/res/drawable-hdpi/ic_action_done_dark.png b/Clover/app/src/main/res/drawable-hdpi/ic_action_done_dark.png deleted file mode 100644 index 4c2e84446bf23f041b76357c44fa8f37298ce7e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 392 zcmV;30eAk1P)zqoZ*u&U;`iBfGvDf z11{jB8E^$3#ehrr;09d7uWn>KV70cD$AlLK@SRCNVgk?6OztPc3Akx1@p*cCO!$8C zv^EQzPLo3eN6mx3Qdu@+vXu6i2({+Pv>vvY2wAYSrKn9zXyBiGUhU&$WBfh904=A> zQekW0rNN`Gy@htXRc2>`qu0R8SsIctuwbGO4R6&-%$N|N;jMcijfr6JK3a}O6>@g} majINHe1sDLV`TCKJ?i2R_0000~)nSPMBK|z4!;0>128*SSfO(WZG({C@e<@zQ{J^CA$J^9^h-4+HW z4uu9V;m}>FaPIT6gtre({HFI@`KRUogk{zopr05h*# A?EnA( diff --git a/Clover/app/src/main/res/drawable-hdpi/ic_action_play.png b/Clover/app/src/main/res/drawable-hdpi/ic_action_play.png deleted file mode 100644 index 9a2147eccf47037a214ad4588856e2af4f4af166..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 437 zcmV;m0ZRUfP){!L~L2Tc?gmY>W|{>{TYnE5-bgMmt=QmNWj zRaG-MVg`ue8@z=leX4Ev32!fmy!0H0; z08;k7g+6Hxp9Gc?;58qBIGgBY1h5*zCUO&a$_QW;Nm{MiirryHt-6%?Sh51x`B=$( zM2rCS`AA%?B|ZS^Ysu-~wZtcYRV*M2RscI6Yd{=-oe!6*giBpyzq+%$fyN4ZR!<=d zVa^6%HrPE1KQq386waEi;XVPb^3?BaGw^^nuD;;Hj{Dq1W5$?5nH2B*bF*!LTw<|c zI|m+8_?7J-DSWA*uZ{aXO;KR8q> fl}hzVPXPu1yws;8#Piok00000NkvXXu0mjfk6gL~ diff --git a/Clover/app/src/main/res/drawable-hdpi/ic_action_refresh.png b/Clover/app/src/main/res/drawable-hdpi/ic_action_refresh.png deleted file mode 100644 index cd16fdd5080541f0e67ebf3bfc97a50ac2beda79..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 531 zcmV+u0_^>XP)004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00002VoOIv0RM-N%)bBt010qN zS#tmY3ljhU3ljkVnw%H_00E0hL_t(Y$L*H8N&`U@hX07hLJ8QYpqOmZ*^79od;tp^ zb%|K|0D_Rp=xbQncq^;|UIV^E2ncpc1O*Y)CMNkT9HN`dY$94Hc&1o(=bUfn%$f5u z5%e?Gp?}b?040^tsY)uVqFbFQBQG$Y4ZL9=9tTuuv?@EqjmHLjj<93Wyx_7Y77&}z z8nk9YYUJ?o=%SMZKF4*~iFt;C(#EO4Skv4zSAo@qfIO4b89mmd`?zTjv~O0^<0!&r zdn-y(1!|V0J}T7~C<8#wfyp*i&bA9ge9pQ2f VFoeR4ydnSq002ovPDHLkV1j|y+zbE! diff --git a/Clover/app/src/main/res/drawable-hdpi/ic_action_write.png b/Clover/app/src/main/res/drawable-hdpi/ic_action_write.png deleted file mode 100644 index 3ee3e1720bd76cac1d0ba20d1315af562512663d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 351 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K;Lb6AYF9SoB8UsT^3j@P1pisjL z28L1t28LG&3=CE?7#PG0=Ijcz0ZK3>dAqwX{BQ3+vmeOgEbxddW?xq+X@R~r-W;^-qY;7chg60 z?&cYx!Ygtoy_Mwg^>;29~AGdj*J sn^^*T|k0wldT1B8K8l&6bhNCo5D3%fZR5_nu6GTXnn z)U>ihPJZ*vEHjU;Xpa-Nf7v`z+Pb!Kg%oSBYR+9u6~ vKeotrpR%h~+rO+U*x6Z^BW=wWuXoIeu2U7w-_4f;+QQ)J>gTe~DWM4f-d!_! literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-hdpi/ic_arrow_back_white_24dp.png b/Clover/app/src/main/res/drawable-hdpi/ic_arrow_back_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..a2051cef9e8fac97f1259be5c8091d6ab8e2a9d9 GIT binary patch literal 152 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K8yr+v}h{y5d1PRu|LVxmq+;@;o zc39A8b?ndo{U7a(OM4O*w;9f6n`$__eX(KmisUof|K~0c>6I5UYx8iZZVuRU&9CwL y1*X|^qa;hOtXP;Y0@Si|k0wldT1B8K;Lb6AYF9SoB8UsT^3j@P1pisjL z28L1t28LG&3=CE?7#PG0=Ijcz0ZK3>dAqwX{BQ3+vmeOgEbxddW?v6yN*e2orR zA?WO2{V8r{`Te`zMfx8<{F{7lmV#rKi{vMtt{F`%s%C+&rtmGjaqJwACxcdUwkX3T z9!-WRg~{&OGEWrPEnidzI()DeDO|k#vDX%nPnHGs((6R4|5OH?>r5*NGM72|c47J# z5fv4YFSkzdta$oq(^bP0l+XkKLQ-}( diff --git a/Clover/app/src/main/res/drawable-hdpi/ic_bookmark_filled.png b/Clover/app/src/main/res/drawable-hdpi/ic_bookmark_filled.png deleted file mode 100644 index 66d4223d1e24c034a977d635c77ef2a81c835fab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 273 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K;Lb6AYF9SoB8UsT^3j@P1pisjL z28L1t28LG&3=CE?7#PG0=Ijcz0ZK3>dAqwX{BQ3+vmeOgEbxddW?Tk)5S5w?TEnA$d zw!d9S`0U0)mrKPNsS9>ZNk4l)tMyy5*VjGrRm@v00|k0wldT1B8LpHcuDF5Rc<;uk7Y+HV|H>P~`P0WERgjW%5sur%i}4*z7Y7{qty zep~kWc_utr7KZ=kTv2wHs?RuiAt>lllARyZg3i;Q&U%;xTbKlF{%LhL$oPj-+q6qn m&wmE6hbXkVdvFPIzhPv4=E1zK!Qw8^2MnIBelF{r5}E)FXjvx! literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-hdpi/ic_bookmark_white_24dp.png b/Clover/app/src/main/res/drawable-hdpi/ic_bookmark_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..9de15c51a92bbc29536fc7a8e34da51f1b6961de GIT binary patch literal 185 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K8gQtsQh{y4_*EaGtCXxw1 zJlv$4!kF$T**4E|&JoEK`&v7DIc1K0vU?gE=foPj+|<4QurOEp;fvR2wk!!*Sl|(T zYJ#})J|0#>5s@Gd#a5AD?5A9Grg{A1oBPJ+{1E|*+Y6hgJ~Wk$v|JLPmeg(i-BtTS ikD%?Fw#fbFYh(9%S-#0z*fJ0376wmOKbLh*2~7a_ZbD%I literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-hdpi/ic_create_white_24dp.png b/Clover/app/src/main/res/drawable-hdpi/ic_create_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..d3ff58dccd3c40504d3f55a4be8e0b79e3bde9d2 GIT binary patch literal 214 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8LpTu&Fr5Rc<;uUK<67znUjnB%lT zoOSjO>jray$uJw$FFVMU;3(SEsNVV` zY0pZ=3oE8p__*1#52{6WCQLy}71A z^UjP{%xC@x1hXWnn6M?T5oq1$VC;1(TE5wU%_Uvsiq|WdbN}v4kacX7_2athUkr38 NgQu&X%Q~loCIIWZPKE#g literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-hdpi/ic_done_black_24dp.png b/Clover/app/src/main/res/drawable-hdpi/ic_done_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..d4c06072b56dace7da1ab5fcfc5cb0a494adc5cf GIT binary patch literal 177 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K8g{O;SNCo5DGlpDEh5{}R!&SuQ zX|-?oV07r-F(+5sYxQj19uA4F0*7@nHs;@YsQf$gW>+px@zP|&GZEd1Z}?}-I>Y|V z=y1-BV5J$-bD3R}6Ta_|*W@zZWWK6sUb;=`BCRvpTf-#$b)_C_PW(7UG2P#7{m0nI aGWJPksgEnI&wc~Cfx*+&&t;ucLK6Uc3_uP5 literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-hdpi/ic_done_white_24dp.png b/Clover/app/src/main/res/drawable-hdpi/ic_done_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..c278b6c2b30ba9bb52391af71120270e908a7502 GIT binary patch literal 188 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K8v!{z=h{y4_R}8rt40u`}^1XVn zvWkOUU-^j{pVq65HqD1Oi)r3+T*LWdLcQO)Q$gY0SWi# mI0*h{o5b;0Guz~Cq_l|d_dwzLnQwv4VeoYIb6Mw<&;$SqxI>Tt literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-hdpi/ic_drawer.png b/Clover/app/src/main/res/drawable-hdpi/ic_drawer.png deleted file mode 100644 index 6614ea4f4da2ffd9534f0ef5f20bcb00194005b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2826 zcmV+l3-$DgP)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z0000rNkl|k0wldT1B8K;Lb6AYF9SoB8UsT^3j@P1pisjL z28L1t28LG&3=CE?7#PG0=Ijcz0ZK3>dAqwX{BQ3+vmeOgEbxddW?$M34UQE3J=p25@A K&t;ucLK6TzyF#4+ diff --git a/Clover/app/src/main/res/drawable-hdpi/ic_more_vert_white_24dp.png b/Clover/app/src/main/res/drawable-hdpi/ic_more_vert_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..67f07e473442d1f5bd5dc486a42ce4bedf40b425 GIT binary patch literal 134 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K;ucwP+h{y4_mv-_VP!M4WR9aA@ zB9L2TV$k7bqBi~Tf{Y7K)@EPe&B(sMnUQ&cV?}1b!p)H;o34MJ iAa}{R%7g#se7OLo1Hz}Zd6xqXX7F_Nb6Mw<&;$T!hAw^p literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-hdpi/ic_refresh_white_24dp.png b/Clover/app/src/main/res/drawable-hdpi/ic_refresh_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..ffa7be9337df524557807b421e8f0c5a5f53ed08 GIT binary patch literal 387 zcmV-}0et?6P)Nkl9LM4B;APNAOe8{k>Ka6ZdoY+NjnQBvqLY`~Fj)kHsiE3P+(RRg*h+08!O+I( zho6SjasKC2x=Ei$>e7EgnjA%{)Oq895;;7zU`O%rIKd~#=a8g6u?vdBGOxHivmmj@ z2SsC(rUrR3c=XakiVOw5T<}RzSf;7Wqym`bmKJiu;}uh4Kp`07j&E|~7*l3Iq1dB^ zTu9>s4JH+eU4D=YIZR%m*dahJ6fqfvV4Gj$LKWkwQ`9lN>J)WMpE|`oCaq3U#4ITW zE0|Ncu!T8O42qaFxsbxgOeq30m^#C9;|Oz2LJkaagV|RUlDuFpNhkz^Twxv=Q8Y3% zT{Eo!X1Kxl%qbr0d^sn}1pV|eL6!nd4OZ127J0_yiFvh;aSrhbdgFjm{S`?zDNvzC hjS6RMFs3g3C-2Jk?*l<_)DHjv002ovPDHLkV1oL9pSu76 literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-hdpi/panel_shadow.9.png b/Clover/app/src/main/res/drawable-hdpi/panel_shadow.9.png deleted file mode 100644 index 19ae66300e97a8927517c073f6ce04eefc05e79e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 111 zcmeAS@N?(olHy`uVBq!ia0vp^`asOe!3HF+3T*uYq|7{B978H@B_}jA{CDO#%*d5K zfx%57jVVb?A&oi7PvIG35~G3`TTDaJY4;Tc>`U@6@Fr2>`Sdx1t5d?E(BnvfCzDRGF6gF4csf$in%H4Xw827`PE6p zqeuCAn1O%?;7&EP$#lkYy<|0Z);ThuFh}CN%NA<4lv+~3Q;3EH14|d9S(1s_O@-$m zPs-+yQzn`vx4i-WpD*9O)t?U?7nkCBV z^b8Bia#|S-T}U!VKp;FoIgoT0gV72Q1e9fVM&YDb^%1b>nGe4|_-SF;A`S_FM}mb2 z0`P>EDZ&t84p;(=gek)W8W7Fs1|$<`Mi~SGFad@v5->?i`;Zx6PVt9Jm>Woo1p1fA z|FF)M<}Sv--+T3=i;sJwzQDA=l}+C)p6BHgc-~~NrMP%^fCS|fP3J#O2jl?H$An36 z0tUh%89={Ue_4bGU=H#zfbXt3+5)}>A8x>=ue`9jh-^;iDa@_ry2a31?eH#lUI^Yr zy2D)|dlrMiJRv(^0hAMRWCoFeLJ;J%oRBynY!u6I{Oc#1r`I$vfqm)mD)N1MQ)|yg zJbUA1UQ1+pP4rpC({^TE67QC<*_1ou@2!z(A7OqsVE< zaq_!Xnk!pws@>m+-5p>Xzz{_B9NX)Twj47)E7;5`ZrD2O=_zGow-VW=72cg@&db)K z)5^9Zib_?bbS!nVJ#`0PZDj!ZZ!kC2V3Btlz$Uo!1e~X*z$52+V_Pc@sji2 zhj%~T(FD;p>1-3nuY2!G~@g|f6dXbm5Ocer70icBh+e9-T6hLqB z`~nN?d^QYY?|I(mC9@oBa&4mB=r#JI9Jy~1X>ux6rBfOzsH&hXCDfl0Ls8Kq)*qXu zDLS1_;`7yNC6>!2Ehqr$_xp*@XR{d^6!$5HVkm}UD28GvhGHm&`hQE0ZnrBe%gR+T zMDW+5c+g}r5w7dr$5T)dREVjpK)IS9CRiSz+h(H)L;<@M@NxfM+HSY_P_R>hwOhd}UxuQqqY5e{ z4i%`NHc?t)3LVGU|A0E5###_k}@P)WGTdQA{hJ^ZmZ;~wAP55H`+jK+ zTr3tWNfNs#01b!3(opO5+CB&Lv6QP`@?UwS{+lK=yW=4GMTXHbjsp5#{Z%K z&}=qiuInCiI7f{-gIcZD@f`9pV7x5QIm&=pLG}B6BPa`ldMHqX!GMj&R|>F zMNyv1QYmG6cTd@PV--0HF6(|_70fhdEP)Qsy(YKK# zNsMLVsZIwgi=t>p383&AO9qR6aN!3?#QME*2eEYGjVrDo$kZS~z8Gs{`XRKMj?iGUvyz$O z_bCcEd`sIAGKLjMID=RxzotmQE*0n>MLpK?-(WvMO+nO*BpLH7t-{$uGv-bOn8fr2 zGmyA4rshyIa~4o@mt%9_$ljcSo0&I$x(3kTBm{{)`?qsJN>-CcvBz;dsDMBq5C}d3 Z3;?KqV7eI%afAQ>002ovPDHLkV1hxPpUnUO diff --git a/Clover/app/src/main/res/drawable-mdpi/ic_action_attachment_dark.png b/Clover/app/src/main/res/drawable-mdpi/ic_action_attachment_dark.png deleted file mode 100644 index d0d8051af57606f0265789a0e60c803a6c6bf246..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 379 zcmV->0fhdEP)p5$jBPJ* zC^7OR=)%I*qQf1<=y5M92l8jD15B>D1SVn@um!d0AV?dCpj?FYIP`-*YC1xLO+C77 zAb)Ogz>@oN&^Hv;5aG?(toc=|VLWPZH{{Z^QzdBV5Y>w;Gx8<7kU40^bn+X5_=M%b z_T2}i+=TJYuc^7YtED-R7&Wihl|3kJ188;#ZQ#IiamK`rr(jXxlP^(co i;9#_4GU@<;00RI{VT;Q4srPFD0000<|{Ln>}1B}lL?PFT_O|NsBbOog``qW1B0oM$LxR!uXU zm~1&=7Uz+y0LAJBGelx#8jgNC?=a`wi4#A1V%QCW4t|QB;==gYAGPbXFRCwBAU>F6XU=$26V8kbBY;0@^ zq{4u>@9f#Lk4Z5Ys8<$96#?-opx)!S)G-k-2V^-H$RMbJq*~4eHG_d%2lN5)H&Psd zX8AX$88`tmKFR0LpMR2)lDYX-@nh*(FEV>wX{AjT2oT23$* zkPyFQSx&M8a5#d2T+4}$0s_&&O0MO^WJ8(*W-3I%Z(_12RUCjL5gsSDoS?`7xUw3l zg%w#2Ae7H3aRf7^mQ(5oW@=bYi6aPQLy}84s2Y@7l#+5_6*+|rnj=YcL aAiw|+C&DJQP0oz~0000<|{Ln>}1B}pV4FnQGw$lhbcF#pN_|NmTvlOA(yaXHp7=YfQzWd6l13QbWBbF5EntH}^M8nLKhNl}v$ z`vZ-XOPZxe9-MDujuPO_2=wV|3@K%?U6t&_#+%cevc=Z|mdKI;Vst0JaBXn*aa+ diff --git a/Clover/app/src/main/res/drawable-mdpi/ic_action_done.png b/Clover/app/src/main/res/drawable-mdpi/ic_action_done.png deleted file mode 100644 index cf5fab3adf243318d11ec95448c6deae3f52d9b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1197 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWuD@%qp275hW46K32*3xq68pHF_1f1wh>l3^w)^1&PVosU-?Y zsp*+{wo31J?^jaDOtDo8H}y5}EpSfF$n>ZxN)4{^3rViZPPR-@vbR&PsjvbXkegbP zs8ErclUHn2VXFi-*9yo63F|8hm3bwJ6}oxF$}kgLQj3#|G7CyF^YauyCMG83 zmzLNn0bL65LT&-v*t}wBFaZNhzap_f-%!s00+w{G(#^lGsVi#&Ct}+$imXp$-u?X(ACh=#L&{!#L3yw z&D7A`#K{n**Cju>G&eP`1g19yq1O?oUQlAlEdbi=l3J8mmYU*Ll%J~r_Ow+dZnv1@ zG!Lpb1-Dx)aO%|uIz}H9wMbD769T3m5EGtofgE_!Pt60S_ab1z*4|&C&cMJZ@9E+g zQgQ3ebbs!H2{Omc#n}0tv`#21C~#0@f8W4;a{i~dB^meHw?8lo^y+Np_VX($n(_YC z@+E&a+Mh40ocC+XEx!5ZZ+*78?c#g6#lYQ#qw)iToIq8>mujbJsbce3PBczkwdxup zkDJUF2f-x=jZU}=Fgph@h!N>j@?Pr!beU|A1vJvL35&6;ySFy-J4wL_Ed=se(2D>)PC;-R9y zdup`rq1*C;xs&W09=YXh=ju@sDp||AN+rHQcJ=j-`9~Vw?O~j!62JMM+>gE!%~B^t z*B7ZvUsQj@6<2p>=j`nZ}1B}lL?P7vu~`SAaLeVl@yw8!b`j2|Tx@*Jk8 zFWUOlAxlkQwPWi!zA5J&Ze6VcFTPZtRc}1?JvSDAtwC4+o{u&F|yKCK+mXwquU}R%>+m>-ZX1@3)pc@%HUHx3vIVCg!05Z{8^0$x%HC5M zDbb1y96PG#E}b*crF~7D(!F;|OdJXg4Qn5Lbvcy#A}ws*s|Kr{TRL)zK;aKt8+M77 g+o>-wVv%4tbz9`!VZkj~Kx-I0UHx3vIVCg!07CUbG5`Po diff --git a/Clover/app/src/main/res/drawable-mdpi/ic_action_play.png b/Clover/app/src/main/res/drawable-mdpi/ic_action_play.png deleted file mode 100644 index b94fbe6e38881055417b18ebbefc00a6479b799d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 339 zcmV-Z0j&OsP)wy3N|ML!X z2=o9Q(Lig55Q+jHAl?LYMA|^60Z<5}0Ufa!h>Zs_5lRB_OrRq`SZW}1fiW~%im8!4 zD9MJAP=`bgWH|r|0Z>RRBR73es~}Q?rjH&{(+9OnLI+s3B{qG~swf7P8=z?M9mu)> zlx^#w+17Z_Rz@r|H2XOa&tha`+&mBtm<7bkftG)!cL*E+;y$3o&*&Wmw}7}8Xz^Kk zr-9GVcwRmbiEug8^3U|n1)yMVBqg4yO=~G=WkKx z$X}z-W_$b!{UqMfxgg+Y2*GnN7D4e#B!a-54~*{Z!wwfd3NoTilU2CuZ0B6Z_UsBP`#&E m+Is1!bIblNdm{hmW&YvE^KNo&|F$0JI|ffzKbLh*2~7YK7l&a0 diff --git a/Clover/app/src/main/res/drawable-mdpi/ic_action_write.png b/Clover/app/src/main/res/drawable-mdpi/ic_action_write.png deleted file mode 100644 index 85cff0b919dd765d6aa45557d1b47e081d447a4b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 272 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_*1g=CK)Uj~LMH3o);76yi2K%s^g z3=E|P3=FRl7#OT(FffQ0%-I!a1C(G&@^*J&_}|`tWO=~G=WkL+ z;pyTSVsZNH<-NQO3IYy^(>_m^EaBrW-%#LZt!(xzl0(q2DqVfcdvCoK;~Dwa|1d

2t?+KF{Qd1XyO;N07-#Y)VLhOn84k!38d7PJee$l{xLDlK^ z4`%H)@o$_F->B5@xbmd`gl9XyL{I(6IpwFU1=n3B&Cm63N{Y&-Y+m_udZ|Cq3k(dN Lu6{1-oD!M`PlZt94B=K^nw>~a9bmGDy*ICncJ)B+6c;%K;px=~btUyB; NJYD@<);T3K0RZi>C3pY; literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-mdpi/ic_arrow_back_white_24dp.png b/Clover/app/src/main/res/drawable-mdpi/ic_arrow_back_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..d571552fb9c5a5e47b5494f52a5cfab771d5435b GIT binary patch literal 118 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_*1TTd6q5R22v2@=~L)F1xOc4^B0 z|NnpQ7t1{5>=7*I75p@DiN=5DSw%JtMZ5*-t&^n^4|{iuWk$Vf%YVkoprJSQ@Ah{} Rw}A#Rc)I$ztaD0e0sv~HDc}GA literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-mdpi/ic_bookmark.png b/Clover/app/src/main/res/drawable-mdpi/ic_bookmark.png deleted file mode 100644 index ec69d41f25b6c71e2e7e1a9b98cd4023dee5a633..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 262 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_*1g=CK)Uj~LMH3o);76yi2K%s^g z3=E|P3=FRl7#OT(FffQ0%-I!a1C(G&@^*J&_}|`tWO=~G=WkKR z=jq}YVsSe8$9V^-lm)BX4*b{upUk}e-|yt>4Y8ISdycGQWZ7WJ>{=6Y*x>R3))trS z2|w@u{D1fV_W#xmI!#hK|JMKcFFo%?-T!z-k%OxlS?d19f4a}ZF`XgOpdtA1=l@^- zAAP7K^k2F`$-;EbANjxYMU{JQG%QkQ*YX!;WmM;1y-t1khFG9W7(8A5T-G@yGywom CnO#r- diff --git a/Clover/app/src/main/res/drawable-mdpi/ic_bookmark_filled.png b/Clover/app/src/main/res/drawable-mdpi/ic_bookmark_filled.png deleted file mode 100644 index 7b4e65d71c7d51f99689f455a53152d47c367adf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 223 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_*1g=CK)Uj~LMH3o);76yi2K%s^g z3=E|P3=FRl7#OT(FffQ0%-I!a1C(G&@^*J&_}|`tWO=~G=WkJm z?&;zfVsSe8$9V^-lm)BX4*b{upUk}e-|yt>4Y8ISdycGQl$W?_u&Pl{s_tL>r~5n{ z(-|UJOl|(h|Bsi^Q~J1{QKKpN@X7xd|3?~rl8_Gg^2Fh3<{|}#8T?8C`rSuf01 MboFyt=akR{0Q!$eEC2ui diff --git a/Clover/app/src/main/res/drawable-mdpi/ic_bookmark_outline_white_24dp.png b/Clover/app/src/main/res/drawable-mdpi/ic_bookmark_outline_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..9842707619fe6f65f85b06fc20691ec855339a42 GIT binary patch literal 176 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_+ia!(h>5DWjer#JF8C5W^JO6f*8 za6ePXNn9i8=6$!>$vsi1sq|5-M0WrH literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-mdpi/ic_bookmark_white_24dp.png b/Clover/app/src/main/res/drawable-mdpi/ic_bookmark_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..84f16627dc7fef320a96a0950ebe50cb09f6c21a GIT binary patch literal 139 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_+iAWs*^5R22v2@+=>)Iaz?{r|?s z@c(}|W*=B5!xEQty@9ueD%XLiQ|9%%Clen^me~?-P5>$?ao_51Xjx|Qk^y- zdBRlThZ6o?Q|jd-p2|(pELRqpvP6?TOTpK2Qrr9gcRRh0Ezy*ZVPIH1?c-DthJyV- Pdl@`k{an^LB{Ts5yXZdH literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-mdpi/ic_done_black_24dp.png b/Clover/app/src/main/res/drawable-mdpi/ic_done_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..5e5e7cf2b14732802095661e2de6a8c6eac3e8b5 GIT binary patch literal 130 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_*1Pfr)ekP61+1H5jHVwtC$CF+b# zCM^47?|k?}@VQePx)djfTvl$Fv|pmhqkt#ilYKy-z^-GeF>qN`e$ mOkm7ZjI#{k);#6T#=sC9S)hEq`Oa^k=?tE(elF{r5}E+GHZxWL literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-mdpi/ic_drawer.png b/Clover/app/src/main/res/drawable-mdpi/ic_drawer.png deleted file mode 100644 index b05c026c18ac30b1852ca8fd2a3e3efb42369bc8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2816 zcmV+b3;*KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z0000hNklO=~G=WkM1 zMTcj-fMuPav=7~~Ah7&(%{n}Mb=c)I$ztaD0e0st7?IAs6; diff --git a/Clover/app/src/main/res/drawable-mdpi/ic_more_vert_white_24dp.png b/Clover/app/src/main/res/drawable-mdpi/ic_more_vert_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..017e45edec435f227c0fadfa13a4a27353acafd0 GIT binary patch literal 112 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_*1b59q?5R22v2@=a5)L;02{eS%5 z@9J@fU;kJ5AT(P>xJ=eVCD820|N5W*kJjJ67$C*FG*QAUgq7iWp7Wo)^m*JsBN#kg L{an^LB{Ts5on9xv literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-mdpi/ic_refresh_white_24dp.png b/Clover/app/src/main/res/drawable-mdpi/ic_refresh_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..97e42b5251a984f151a3fc469c583c360763aa17 GIT binary patch literal 254 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_+iqn<8~Ar^vn58C=20?J;<7d+)D z!|^{xU``;1V%Y-~zhmA4){=|W3l^Ae^mp#jTxxh`k9c8Y&l00n|Cv_|_|7cq>|2|> zG$hGy&ZUnnds{bdo7Op%Nx$xhX7rv{ZmkRX*#pyC_U6eHJ`TU)xv@j}**}-LJdalx z1PhjOZFyV+!t)F}KkqyqYqH^3?iERmr&WQ;3qCxx^7H(-OkVWYy^TF;Lj5OneM?oA zg%#QC=t>h>85EkiR`kE&hK-Z8-{gFG#8k`7Qt>7y-mx$k=phDAS3j3^P6}J2i$Slg5aGLRnlYQ1*o}Lh(HU>{uKbLh*2~7a(i5&<4 diff --git a/Clover/app/src/main/res/drawable-mdpi/progress_primary_holo_light.9.png b/Clover/app/src/main/res/drawable-mdpi/progress_primary_holo_light.9.png deleted file mode 100644 index 6fb9445773467ceda7aadacfb9754f2d347c7779..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 561 zcmV-10?z%3P)jls#*dQ4ocnnYs5(Ho`86 zCc27}|9XYy`m~5+%ukhBcc__T#ZfXox%C31axTjJ6sxguHmyGJ_SSf)K5>aisqkD^7-ItXY*uv(G^APB_+!~MbG zVC&iKbjHE@E0@iO2R8oRSCxhtJ*~$Y;;Mw@dKh{tv1AQac}ya)aw3!}h(^V$f)uj% z)~i-$3kU!Y-t2q;^n|;T5~hej(mcW-8-ispa8ng?+{95%Vk(X~D7XNc@Li@2<{fAb z%Vf1v{+XYy{Th?0|Awi^tk~(?tXp}Rm00000NkvXXu0mjf_HqHy diff --git a/Clover/app/src/main/res/drawable-mdpi/skip_arrow_down.png b/Clover/app/src/main/res/drawable-mdpi/skip_arrow_down.png deleted file mode 100644 index 3fc47b1b084678aefbb6fce6f7bdf364da603116..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 452 zcmV;#0XzPQP)50000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUzW=TXrRCwC#m?3Y3FcimoWG60=nI&)* zG|BWdnh$`-1BusX#0sOuLB$#0tW^wOgPp%LeV>d!EMxGD~M5U>JrS5Y*tW@~77t0OWZ- z%F?gEfWACx$1{WJA!!v!Z-_8a6d^@XX1{e+Rr51LD|CPEt9=m(=G+{@*RU%-_@6tN u=33&k0uWq_eExJl^U8~)&4`e86JP-C5t}4L$+dF;0000`@o$5 diff --git a/Clover/app/src/main/res/drawable-mdpi/skip_arrow_up.png b/Clover/app/src/main/res/drawable-mdpi/skip_arrow_up.png deleted file mode 100644 index d98671e0ce1a79caf1cb150ae1ea84231f1db790..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 424 zcmV;Z0ayNsP)50000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUzN=ZaPRCwC#*uAQQFcbjb)6fn@xJyC0 zx+{0??Cb;h6z)3f?o;>x&dwb=>g;?Mmx6TY(j3te?oVrbf=O>Z5W*2nK0}Ne0F7cH zCZ6Z5c(vtaJwe|mUcT}?KmWjR2qHdtSxq+7uo$Q8r~ zVV45bmqpGT)EK54Zwrw&d%Q8A93_} z3=xtcrnwk^l<(6c*h3G$PxFTI2FkB!%pFs>NyF3ThBi+qrzn3(j|*)&lI}Hg@yJQ$ zo(xs>pl(Rsm1%v|@*xrH1A|M2i^by8Ri7u>-W!dE$N|2bs?+$U`N*`sX8Bf6dmp96 z6B*5u`?h^Uyx3$BzmY6wiX5jj9<}<4_A(kE zE>d&p!2!pEYbmGxtCWcCw6b!p@0V2hU!kxklS=Tev5JfSw zU73{>h5p=IR)rK-{ zxpp%olgX`a(X=*G?rU?eqAgsJ5y{9(#GGzWBSU^Zb+VbF@dYdv3Y<5UL)&Hv@kxmj*|Y|=T&#{{$z4t6Mq+-6*U zIn%FyMwF35tyk90pjV$Cu^Dvj59oH=u;G?KeoDt-S00B``7bB-T{v8BmmiR>5g(|{ zwrs<_S&G%$%PN~bY0STpHaokaX>2p%zX0FZBzcT5`+FO1mi_21S4cYczFEZM> zdD*_;<2Ksg{vO^w|3$x(@w)dsAD>Qg{qMGE$ut?OhWEFn63*Sp&=+{~)$66}QMrK2kwPEjvW|t=YKC+DYMIozEOyP!1808KDD+3( zzrp-WM^EIDE>Ka@*%eQ@zRqM#3fnCbYqMa>luOmO!^6bFcsx8i_8ixJptSOI!dh;{ zFve+5M7bRW?(l5T(eU_oTrcv#xy=(-&-ihAFSAbXR`$GDSv9`aqG|cYMos!>ZMloT zm|iHd`RP@r%AxlD%p&XihL?N1m#kc|+?vtznb2Ie*Wb$WydFCn6fODAxQ?Oxb@InZ z^~>ALon}k#+-m%8M#a_6&Kp7d-|aJLU!?UzeZ@LvUpEh_yhOLntndf{G9Ik^A(+5$ Wx_6(-zl0<4AQ?|rKbLh*2~7akB1Xyams|L+}iAArccq*H-e>r2{iJ5=aOk)lIH_eeCl|mNR6?`SK_G-lidh5JCtc zBq@F0-{x=~ol*F;OpngFd++^wRRX@lKgd|gSc`-^O9`D}_#aFqbjIO-OE`&yV`>3y z2H{6`!!YbDo`6Lr;h(L(0gIZ$M-_k&KAHfO@KFRHg;y7V7G6~VVt6$HsNq!vAcvnV z06qLH0VRZ=ETEL|lLV9${%QdM;YaqFWP1%+VcsZ*AK7FgAm~Q4%HiQ?o5~3iAn(#a zrY9Mnr3tA1BUt@!@akP*@BP_1_aTQ{8Owi8G2iQtDxfq8lj{PdNSIX^DM7;Q$`HB) zmC_ip1hv{Assz>ID53=Q>M)vwDCKb^3DNokP$WcckU)?Sy+b5-2}xRH0wtKV$Rz6# zx*%a(LcbLI1YD3{x_^+oPwAxIRdQ*SC4>+{2qCrdCBOixs1U1hHqUwh0000< KMNUMnLSTY5^23t= diff --git a/Clover/app/src/main/res/drawable-xhdpi/ic_action_back_dark.png b/Clover/app/src/main/res/drawable-xhdpi/ic_action_back_dark.png deleted file mode 100644 index d5760406180becfb647bc7ed6f6f40ce2517e738..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 401 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+7>zw$978H@y_t2Ex5+`kE%MP-Hk|`(InJ*a@ZR3QxA%5~ zSpu_I0;9$3jHEplhu*yVQ=@;gKtZvR-!Wp_YoH}Su;P?O-|7>evZd0cexLX>{d$I! z;?-%(&o&vmxI#!2k_e+#d8wP<;#n7FSnQam)n|HEFFHo=8Ag=W6W sh*rC92M=_pR@i* zPEjZcR^hV+AS76ZFCxHFf_3;}0xTpT!WR`#QUWS`aRDVHAj6vo$dP~!Zzf=k1ds5h z0`8IE6+U}6SYkz=AE7zA$Wy1p8|=~!7V&gK%#^meXz0%8wWZ964n9e$r4n+ z9g84Tf;flor_-F)OM-ZYj|(39WCq}AtQYDUDT$39RD*!28&48mq(Bf4M z*efW9cy$A|3d4V1o%z@v+C@zkpMKi=gq( z;I)vA(3}bH@|rvKM#%J5*z{q@^l{j9LBw=P%yd!IbXnZ=#fa&vu^iuQjhHdV;Tpbc z`@Fl|n2Wjr5BGg7jj7@Nn$Qio;4%G+3?YONLI@#*kQ4I~U;up6U|mr}u3rEE002ov JPDHLkV1oU%v4;Qv diff --git a/Clover/app/src/main/res/drawable-xhdpi/ic_action_done.png b/Clover/app/src/main/res/drawable-xhdpi/ic_action_done.png deleted file mode 100644 index b8915716e06792d926f397a7b17346f656c86aa1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1546 zcmaJ>eM}Q~7(NOZ>jx?|Mx7)_1qW{Q?n+DPg;FVn(PM_rcwjwgk7z zaExq;FcCM$1T(WNW-4=WI(1VrnIo~NbIM>M*htY0#}vP^FxeFW{X=%i-TV8!d7tO~ zdUEwS*{>~}w{ji;01FLSdXr$+1>d=Igzo{O;<{i~@EK-4moDL57>fgGHrj%N1`;d9 zO*m%rRCM7f01z5Ogb|R~a#dE8&^Q=`4tJ)^jrh+MMR3IR69s}KEImMxFjdYS170y97Bn2l! zc!x&%v?#MN2TZ3~98}8S1S_0`fJq7&qJY&3^{b#9Mqmh$L$E3Vfl;Ljg%NP-kqX&Z zTM25?XHMl3ZW^hb=NS}&TrQW)l_;axQV3D2)etO)%@DX$DNsRmu?1h*=3L=$S+q zji`a*c#N{*2E9fqaL5S4h9>Hh6v?`@WTg&HMvx3dtw7Wn3SD|yrV>#pbjUPTPg|WN zPVv)N+cT_sR%}oVBqLvOnw4(~Yn#0m)vQ=ZC?~O*G{jdJEH8vU^=Avr+i|X?`*2LY9 z7jHvHE29PrBH!kINN(*uSt$Oev6h7iu1N7t^Bcq8%eH4kerw;l_*m?|A2AK`y6?34 zP`@{J#lYB+FlJ}1sp{bG{!_iCO_Q1c_7CzZkyMzhv`>@qo7TfY@Gmt3uSG*tgxNWQc=v|JYQSD*fn7li5 z#PB$#i7UEVf00h?$hp1uLQj2zQtZFGsWX7jD_#?wJrFj3Z4#6Vd{fyGdK_MQaQVc! gtQRZb>MZ20@IqqOj{Uq9k@3ze9U9M z)lmL*9cu(5Z$ty@gS0m0_72Y*2ipFaZ*FFOJmGtrEg@N+t&rB zf~VDorivcQ(D+nh5!jo(T)d>t_y-MR|LI)6<2eD96V+>(Eu1DOz27U4CETR)GfdlY zzQB@`+vB))w~)xp|PcL4n61(4g;$56@AbHzE3QUk+_FtgUDK zp!zi+YO;!F=<7&!_ahatOTI_)Ce$*l>#3Hx>JBsk12iP%PG5BXTiKs4zn|sZ&S7Er w!T#h);t>uEg+PG`7iU&{%bBF&*?E_Vhhc@a;7?}nD~uqOp00i_>zopr0NlMvD*ylh diff --git a/Clover/app/src/main/res/drawable-xhdpi/ic_action_play.png b/Clover/app/src/main/res/drawable-xhdpi/ic_action_play.png deleted file mode 100644 index e01a8445e46def02cebb461969284f628f6d2af2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 522 zcmV+l0`>igP)j!c zl}e>j{ZC!jl~c;c^mt|t5Ka&asQ{ebAoc*^2r-ig;GqiQ8z5}BwuTAxo)v;vNd@5K zD!^4j15rr?@H9yX=M8%f{$L`$dx34SrtA-9gfrF%Vks5C!ymSIZB`Ni_}8X`u%qG+ zCegX?5MLDh!6ZDpM1N>fj@5=h75ZcKTp|G99~$(BQX&A~AO7YCsQ{k-fNOUp5rFRx z$Czt3bpX-VZY}^`*Y2fM0RC7VWbNh%An4l789Z&-u=tCgB(^{cQA6@png_Tt|LEK2oB`Y+c0>D|BLIt~-b%a%&*<)UjKd0IeeM#! zN*jdknD|B7BxvzkYsV^gN&wDia<|mwS0w23I_9-T6+qDOl^cLMb)TmKFlbHX3?Rsw z$`Qb5<10k~!PitS0HUp_WaYlaPwB6+eE^i1N~Kb%R4SE004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00002VoOIv0RM-N%)bBt010qN zS#tmY3ljhU3ljkVnw%H_00H$$L_t(o!|j(%ZxT@yh7oM#OB;7Zi7_}Pu8cndb<-t~ zYFzM7gw|H5E=*jYR5pz+OkDLxXiCzi!L==Zpkg#GG&D?`Jl$MwX2NjqolzE=IkSPx zd*5g7aL&1h2$AVtkq{69{ujV$Zm~|A@7NsigKb*e=8T83;vaCC76ZIuz%wkDwhI0L z2_ABYDs0w>3-uEC16aJpBs%1Xuq?hA1Fq3`n7m_!JQ-$*G0%1Ce01FH)0CeL0hYsl zj{?y##YxJ1@z{?MAVEhi*dRG^muJ}w2B=GUO_O6$cKrh^Z29!MBwh}(gQk4a6+h+iscd#ng}h73 z$bOEVSnIcIL}S$4s-a-l_0ZeZtOt!jvX!p z9e(4~F}I4okhJ31{w9syt6I zFaG|YeX_TQR>*0;&<3U_XZZMQ3J+&VE^urAXCk)nG&@J?Jr#=wJpV0Ns$IpKcW5<8 zwJUsl)+i-wXTjEC&HYDyt?!nI;sXW6HH(h6-Bv0$Jl-;WKG%G-7RFl{?y;ytFI zpSs^u)z9s2uzAn)X%F{_&pQuf=h^Wqe6nPi>d%~F$9e&zY5M*%Od8MF#f4XFO!+Mg P3LpkgS3j3^P6U%rc>gQAlyI{<}N(MZ=^SI_8AdKR>jhetYHDLjKeOh)ZGy)Se>sD~ ti7V97rYdY)!O$66q*f-$Da+KL#xIf1*}haLNFQhkgQu&X%Q~loCIFndEw%sv literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-xhdpi/ic_arrow_back_white_24dp.png b/Clover/app/src/main/res/drawable-xhdpi/ic_arrow_back_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..ce5b878b0fa37a263da66cfe403868fef2d4357c GIT binary patch literal 151 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}b0DI8PVHkch)?FCOG literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-xhdpi/ic_bookmark.png b/Clover/app/src/main/res/drawable-xhdpi/ic_bookmark.png deleted file mode 100644 index f9f17801b76cc1275fa46e9dac720fef79ae4aa3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 401 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}a}tg=CK)Uj~LMH3o);76yi2K%s^g z3=E|}g|8AA7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^+;1OBOz`!jG!i)^F=14Fw zFmigjIEF+VemmWki^))+RlTdJwRP&DYyajr>}iNQbT2#OxhspVPRIv=+tuvSffI9G zK1xP}JnB>Yt;}(5cG^sp&j-0T`-r^QeQF}ZKd}o-Sm$!|30~-mlGoa(E@h#xt}ml- zYsCQ>&n-`~G`C&+7UG#u?(j5Y5_^oM{5q>?bs~Z5rmtDT&!WKal9`di;n#!XjJ&Ik z+Z;US%0Kg_+_fDqBNo5ja^I+8ue?TLL$6^FVdQ&MBb@06#mE)c^nh diff --git a/Clover/app/src/main/res/drawable-xhdpi/ic_bookmark_filled.png b/Clover/app/src/main/res/drawable-xhdpi/ic_bookmark_filled.png deleted file mode 100644 index c5698328908edbf984c6f7dd32e133b34957828a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 341 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}a}tg=CK)Uj~LMH3o);76yi2K%s^g z3=E|}g|8AA7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^+;1OBOz`!jG!i)^F=12eq z&w9EzhD01r{&U_T`hZ2&!4q2@<}RFku(NTxNANzQH^~~wI~@10X7Q*?vUrrda%bbt z2}{_X!0T)vxo~6W!TAx~_Y65EB_0&daqPO=WY2Tv$x)4sVt-N-q_!qpX%fsoXrJTd zt}C%Mp(WBGFF5&1Qy{mS?t&Xl@jR;~)fivev<0x4Wkr8zN@Nq**YZh4!bsv$qsmkr z3)YhFT5b0;vTii|JCSU#_zaWBf;oqTU!`d{{=zd+mqy@&U*ubk`V*qRa8*k15n_Kt_^R>9Nyj$8{J)oPtC)ck*1{h_(=T3qCu zqT}4R?o}up^DOr0u6VTFR`_*e^tF=p>~fKpSIbqTpVIt3RqDq924)@!10ZSefS*}V z{Wqid6rRUk=W3Z5B~3qP88O*Ac=&aPc>C?(_1Lj6edWCDNudn^?gww~XyRL#>u^}r z{r>yoF&BR@YX$Mu{jpS8dW*})y^wphybnKzyP%qk4>yEj`}1}_6I%_FcVkPt%N{XT QpdT4LUHx3vIVCg!03d8-Q~&?~ literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-xhdpi/ic_bookmark_white_24dp.png b/Clover/app/src/main/res/drawable-xhdpi/ic_bookmark_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..872349cca6ffc150af47fddd05a5cd9648619c1f GIT binary patch literal 213 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}b0DIi4<#ArXh)Uf9Tc$Uww3&^)Ep zfYG3F`bPtU9&fG$ZvRPo3JW%}#O(4AJh91FX;%5|n&%$pC6=ajnX<2YQuh4FvM1lQ z&rK=QRJaj**--w)>V{~$4=b2Xu+L*+;dr3x(7+&|;Ba7nL&x!?k4IiM_UXR;PzWCs&hKm{}Ung#;dGK1}q&RP1!jxG{&BN`jM9sN0LV@mN N@O1TaS?83{1OP}SQ~Ce^ literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-xhdpi/ic_create_white_24dp.png b/Clover/app/src/main/res/drawable-xhdpi/ic_create_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..5a06bff5a2fc95d5117ce9880821384626d8864d GIT binary patch literal 239 zcmV+mP(MLbxIU@tZx11_<06E_Cm;EuJEI5KzuPNK$?!{-w< zW;{Mke9afh-**!m1^<@N@NHtL5K^$DhZ|FM=P=&qvIgiFq?I{~>Up@NR&` pI{_Y_4KVpkfXgQVHXn-(+!KC0r!M+UZ~XuO002ovPDHLkV1hXhU+Vw> literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-xhdpi/ic_done_black_24dp.png b/Clover/app/src/main/res/drawable-xhdpi/ic_done_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..64a4944f7531ab9fb745fd34dd00c778cff1573f GIT binary patch literal 188 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}b0DW=|K#kP61P7xwZt8HzYxyd7xd z_anOJT=vF;=6o%TO%qmB2=N*^J(z8E{F3t0DRy@o7f;`BG-3LF`^uk20(J8L%76ab z`e&B#*^~M_=S=wbCso$$yluDh-ek*SNjhm@r zV_;&2g`J8435fwA#K6YFz(2r-U|?WD;+({Vp(+xV?Yn#TzVH2hxVCa*W_o@a05H>B zwpx6J**7)G|4G09gD)3Yy~Eb&ChIvd0j5Vc2y6z<7HJX3+rR&TECMjm_1hiRv2S6Q z2BMSch-naUGyscBY2>)uguxB6<%fpw?e!Z0`ko=&Rc+ahYNYEg_hYi&UunDjZCCe% zrE738#hf4@%z4XMOc!0y`I=BiZtGmkgn?)hoTg? zMj_b`nUfa6WFcp;NaDtR#C#gUjM3SkyUY-{r^66}$hMD&!(@~wo-!$QA_#@0zgL&>wHk2uHZ}4jD^P)IA7Ik+660)Xc2>eF$ zd=J+()v{F7D9Q@bDhO5NN>Mk9W(ldPrZ&`^<2bBVDwlOd*7b&FB2-r@wNkyRTUte_ zmdz@%a%?k9m=n4rx9fAeBW&eFEUv}GVKi=2x|4UnT9-1KbZG=@>l(adJFXvQg3DQf zhVfb?_V3e=mU3>1=b9@{%=^O5ariISQh`ZfrR?hxs_miKSeSdnFZM>z< zz59>q{f@@!IrskAElpYJq&KPiiPBCFhMgWj))Fp8FZP&!(u-Yx-6=N#I*7s3)z4*} HQ$iB}uzOqu diff --git a/Clover/app/src/main/res/drawable-xhdpi/ic_more_vert_white_24dp.png b/Clover/app/src/main/res/drawable-xhdpi/ic_more_vert_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..efab8a74f794c2931d4cedf69cd30895801c4df0 GIT binary patch literal 158 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}b0DR8JSjkch)?rx_g|6%VwoI2{_d>%srJ7&|&vk-TbVh<5S;l;%8hhyk$Kc9U$ho zN!;a@as7tMKN^!>mP|UmC!qU^(pC>$p{$8fOT;)oR_iUC=UG0_`?VR+LIzJ)KbLh* G2~7aOZ8w1c literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-xhdpi/ic_refresh_white_24dp.png b/Clover/app/src/main/res/drawable-xhdpi/ic_refresh_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..1989184b14751617cf6e19e833810f91563f7522 GIT binary patch literal 509 zcmV(sT0)b>h9b-n(poNi8 zG-zQY6b*JU4l5e0V&oJJDj3%k4Q4T3VPt|orM3o^7Z9?FUlo?v_>EjL`pcT=Gl;SRnlaz&CFzDJ}KfN37%TVq`A$WX`kh6{M= z!6=v6#el|o1bhI``@OGFc)X9DQvEsOU$8q^tdCHMdU diff --git a/Clover/app/src/main/res/drawable-xhdpi/progress_primary_holo_light.9.png b/Clover/app/src/main/res/drawable-xhdpi/progress_primary_holo_light.9.png deleted file mode 100644 index e62123c4d45d4de95b73db947f09cbb7edc4113c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1285 zcmV+g1^W7lP)w-zSTJ4{Ou>Y1deZ-!OP+`@z;1hy!P?u zgkjs@C*+1<$HFIaO`2)AU`o z3QxzAVcgE^t-TNH-X_WQ>)AXv;T_->Vi#Sy_zoA}*;3!YFx!U*CDuBTtBM@W>6#)> z4>>G-r0z4DSn7|YQB#J34u_e7LE}`U5TTH&6dBH5jY3LWQJh4!-E1y1Y_T=Z!{8pz za+Ph1U%|UKQM36kWmltUkn6gJS*P*2Mq`Eg>eAFuUx&yN8oQM0R5lc+!tM%^N<>LV z7(%KctFdd4Q5+$P8`}|bktHY=)TB;>oT;+!n9M);#peFgPy8;t{Q+Eg6YY;TbpPN$ ztLM+DxQWTAQH)ZkM&A)`i8_xGNPT1h2SEYCb^(R$Mjj%GLJ&ZMA|x8ilGR{G5UoMT zcG}3rL=&Nok^*P|-uu%he?6h9$K_K2+%>@$XtgatXI18^AdU$@1;V6ak)>oWGc!^umr$V$hO713sb-fBTa73*a=W#p9jii|RaCBObAfhxnj_=3W9YulCR=ajQmk=!ly0UgM+P67|`xa*EUD>Nh9zfB&&A|F^IkKPJ{#z{~b zLe&tpmuB+Ne>Q67cbYA8UHOV_tzjGZ!_vWrYrl^!ufWDG9CwHf$OrrMS3<+*()SOF zI(6}*OT1Gjg9k4`tV z4nGFwXyf0gA5Y0+!FSdf))syF{FB~wH1(Yy{UG_{t1lXO_5ZBk4@}xo!OqnrV0ATB6K?00000NkvXXu0mjfl%{@_ diff --git a/Clover/app/src/main/res/drawable-xhdpi/skip_arrow_down.png b/Clover/app/src/main/res/drawable-xhdpi/skip_arrow_down.png deleted file mode 100644 index b8105c86e43367734a53e3541d6f400362b9187f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 705 zcmV;y0zUnTP)|rT1)vVv`v4e#G4O3y+9*NiHAX zy~{oBWDJ5J0m{V{HX4ml;g|a=DziZmZQ|tJNxT{qcCbu~dMehE%K7gWx2U zZQIJB2<=M!eqUIlj{R|{4XKPVy5NY0A|?2$h9d)tv{8u~IvS0nL!o=ffFgCc9t;N3 z8oh;2_c+V<7+G$vqPt$4TMSSY!<4-Fih`puuq&GqoC-(vXs2|pbSxYl??=j)fzSie z+^5}cvqGT|TbJtfdOdTNflMY7*6DO&Cx=u({qA5lO>5V6-y*>T z|8?LS23nqZ`M%()N$D61+S?E68p2DDza{JB> ncCcs7d%kvK3Ist?^drCkyh#BCaTah{00000NkvXXu0mjf;^{j< diff --git a/Clover/app/src/main/res/drawable-xhdpi/skip_arrow_up.png b/Clover/app/src/main/res/drawable-xhdpi/skip_arrow_up.png deleted file mode 100644 index 5d40a66d51ff913158d450553c703414b8794f26..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 690 zcmV;j0!{siP)m;+8qJ?g_WNMiura&q z&zVhj$jTT5K>;Y^b+X-V=S5KwRuYy=$#*^o+X!3ex_I|V^81suca zq~>zbXUd^4I|Ay$2|k=ozBqWxyC|v(O(#Xp`Oz?pUssQ@=ad>#PxV`&R8jOMloL)- z^#W5;_zqq40+VBq=UoY4fB;|sCJ1GpZJ^WXSSFMD{XUz`X7Ct zO2jlxc+6RiMuQE9L(AwGV1!z&78?u(tWYReM#ogAG#CQV>-DbcsV;6fnru*HfuqR? zMFu#UtWe^Hqsa^8i00v+HCR%0V=ybJO-JJ&A?RM&b znNFvcA(Sx301UtY%t;3zaR#$dn8nr$%z~YEu&btnuIo!zF!p~PmoP_978H@y_uz$bK60r?Q#k$x8#chDY{D(Sd}L>1>LyN zBi7zGtw&@UTR%@pf{MvPMQM)6B|IgUoPsqqQWmf(SFf*{yy)GXIp@DcS>IQmD`ffc z=D+)QtKZ+-8N>*51QyV+X!G!ojLht&bGP`=8g|qzoIkQ zt*ttiUusM0nEgMCK`@T>{rdwM-yM(sS8$6^vE4ZB(A_=Lzj3{Ne`9)?jO)d!tx>Vh zvlxW``$Wm!{l8Gt?T4bE`EY8fHIqCE!%^WEc`HpI-Df%_Zhc>rd zum9fgV`Wod;D$Bs^Gmgky@-Ccy;EwbcJ7pw+>^R9mmfD|e6jh?jfiFU-p772|FoyL z&{ALb>%AviW&Xcf>~4DSYn9>g(kuSuS6`mq96#&!%_Z+&wiXw?5@j zxKI0nNiFLcV_sgfF=%}~%|vF6?D^Y1xeU=2JJ;;v*l{wf^KoH-?iqD9oAV#kq$95d z&b#nv%{!xp^Tt1SEQmh7F|}>+li-O*&373xYuEC0XsV|~R_T2?b<^#C=i}wBYHS^x z248uO+G*|hQP}FaUgc=H?1nw|ubw{Aohj>Sys%YS;QNyGvqkdWZp?`AdMi}_cDKV< z(*t)DW3&}Sul}EJ)i-~djee`a^8FTLZfS1U&(8SzU$$uuTIUkk6JXfc;CtE=9l88c+}|n#Hs0? zye`C1zB=jj^~2TnvTAp^ug;$G&Gr1|2XP_JFBV)m_{C5`ai{XjX-lLY*rdrWcz=RN zd%}FiGaS6ePIsyjx15$X*(rUX=fX{)hJ2mkpyoe1JKU~UzAIi{X_!4*@YErN^HHIu zUtEff#it(VqhAE%Cf==yk437`Lqks8S*gXC1k^82*FW)A* uJoMbMrE6U4imL*e{(>?YHgIC1JrfUu-Y!1#9~!c(AQhgjelF{r5}E+gPM?$j diff --git a/Clover/app/src/main/res/drawable-xxhdpi/ic_action_attachment_dark.png b/Clover/app/src/main/res/drawable-xxhdpi/ic_action_attachment_dark.png deleted file mode 100644 index 305bc41a46603a4838c6a338e5390694e02d7ace..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 822 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGok|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+m~MEwIEGZ*dNb>6;UfcyHp9)~Tn$V&m|_kDIZU$FWVk>5 zjwe^b`;WEGj0+oc56gVX}RLqm?O?OH<^xNzH{Fh&WwqgSd zUaKt3+j2AKSkcaDOV?#S*(JKkD{{4p=c>t43Wu~Wrf+H!-_?12)3hX)+7M=!9}{E5 z#5df|4S00Flk;dG&xME20R+ zG?IfOvM0PdQJudjFSod9HKYHoQ=Id9tg?>njaerZcgnThW(DJ?wBVg*csXB8&wkT= zhh^!>-m_^XCmD?opVtrjv)|gn^IhqUn`sFalK(%RU3g7iqVLw`)yG)#nbYt=kY5&aA4lTxzsGNb&9&dgT?EvUp?Pzw#e<8@{C>%$%0y<4v~yjNJ$oBx>mrSX!F zkwLsSG7?uCOzmy$^-beG=w{$(^ZeZ3`iLzaT<4#waip0^DWHvHh#J?qfLcV)bQr9H={&6$AKSC49CQo z4E6~$d~9Xt(Pv4hQDk_`jVZ<6XPziS+_-)^1q>DvCie~upZ|6O`j{{NNv-}x9gk{KF+LEOa1 z01RUV3A~)57~eFO*`J#>DMiTMm?C)a-H|mp9MjyVr8;e}HP+*9`ns^zU7^O!ddvBL zSB@|Xlx@9M9oJ;S@%l&fy%tlB#N+&|ADEq9d^~J+>El-y1Td+qW@KY9-@Rk0!#@8v Qz!+xmboFyt=akR{0OTvy#Q*>R diff --git a/Clover/app/src/main/res/drawable-xxhdpi/ic_action_back_dark.png b/Clover/app/src/main/res/drawable-xxhdpi/ic_action_back_dark.png deleted file mode 100644 index 4919a8d7dacc294eded63af5253bb1a4d824f0b0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 463 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGok|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+7z;gJ978H@y}7f|_lSdt>&30bR>`k#FljU_Wmwf{w1Dx} z0tVx09VdJ~{rf&gJJN$=QuzkKNi$EoPEzp%qm>D_x5XYW-R_e2r~m$H+e4Rf|9pJ- z^ZfGr(^GdcpXj+SmuPwL$6CQ_lY91mx7hcM(;@B8-uH!jD_Nc%+u!ScL7d_7ceWXs ze~K73_r`N29Q$~h;fz%sXT!|n{mf_V>O>CwaAbJQ&e$W*Vo)c5m($Svc>c!o9}k!O zK5xG6*!gWz`!yRra^GR(V(N*v`kmdNuf}taQGm;)N#Tbx4?~L*g8&zUg9Zb`LI#Ew zCVZSfv$Yy-3d)2sB;>IizsfK}df}IawZ;ll>Wtq#(AMXFysKpF diff --git a/Clover/app/src/main/res/drawable-xxhdpi/ic_action_cancel.png b/Clover/app/src/main/res/drawable-xxhdpi/ic_action_cancel.png deleted file mode 100644 index a9bbcde5a0267fbd3c4c6509ac1c62acf46f150f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 567 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGok|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+7;k#IIEGZ*dNXHt?qLHFSI_A;6@yoJy>&HeX8*_&=~AlY z`%pHfoh@Pshs;H>pYOJwV`TZC(D7dGud9|S&<QojJWq{W$G32b z+5V~1gJ(Xw^ejJ`(e%&xUmqVSJPiNw{_E=X^MpPv_%OM-#r}~0Ueza!552v22-k&k zw)=gRdH<(O`$GtK8R!4~v!1Zbc|A!_KQZ;k^r*>K?Gj2817|C@nmr5G57?Vqso%P4 zo96qq30ql}-e*n?kCATY?BH`Ktv3mA2oX5N&U~1)htK72frZO~6$vuuTo18);X9%D zr+{&9QxRvp(}8P^maY2A39BF6IW%49Lrz2A!_%AHd(*V&b)d^ZzkL#%zY!3T1~l9vDm!He@N#Jfu^j zcZ{=T|IvEE2|E;%<@c>-$vgG_=Q5kSK`&;A>NT$GJSg;Hj+UDB-^Sh9Nb<2H?#IoD$9}cKB rE>@6>R4b4>;QSjo7J%#o8+#@m23aH3DE>zRz930YS3j3^P6#a{g zR;!|d;+#c=g+U@&8#qlP?>iTDL8fv<-j3NWs1Dzp&i6b`Uf zX#a4S^$OQ1)f!I5VD@Js`+6EyHWhQndmY%!Xw{~#{@|iQ?BVGm24)xj?M?l$iOJ2& zW8Fh#s{qD=Ojqze(iZm7@2I z%I@218TfOAUI_H-2v0oV{2Mtkfb0dj_nCMYChW}1JZTwX29or2^>bP0l+XkKmnG>o diff --git a/Clover/app/src/main/res/drawable-xxhdpi/ic_action_done.png b/Clover/app/src/main/res/drawable-xxhdpi/ic_action_done.png deleted file mode 100644 index 6fda89ec7d8d2ef1caa50a1191c1b2f9a0e65e2d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 649 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGok|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n6y1z978H@y_vn&?@)k*!|Ik+M|N2r&hGUM-TIHt7{92t zFt#xG%y-U5#fNXrtdgR_gu;*6Ol=dkEd74(-v0M@Q3OilarG)?VsosHc6X{kFE8|r_utCc zb^hr(TDA9H+1%eud(S;t@AFLE!QrP&)2yfd=O*mmGSR;w?dN&j*=t???S5Na$gyg= zeb&VN1s`izI5g%nG(Htp*igg7GHtz`L&ncl%tsXBa~mR_tmYAzTvN)JG(^Jy*f2`2a7taYt1E~`Fiv++F%=bn3Gp8Vp#eT5CeKiL;`Oqf)& zn8EbZ;*JTk{%}p+uaf_5ao?*sCnY~sSFxVB_gA_4XZxMn35IKKo_VdU82aa~Rq{bZG@b+P#Mt@iqco6CE4p82`js^K+H4XA>%&#t@~3O;?3l3o zPaN|Nw+jmUzcVZo+;U?5hi}uL?37nb)!BODyVL^bme|veZ=U#G#9?G1!wVFWTj0zh z`l*@4pl8C;KM9OhZYRR(E-<9KortRYz@RI*X}Y{?!z>Q1C+@-zR1Qt;*~#`3B_4sC cpP$qZFdVVp7yd2n{x6WEr>mdKI;Vst0Qu`3kN^Mx diff --git a/Clover/app/src/main/res/drawable-xxhdpi/ic_action_done_dark.png b/Clover/app/src/main/res/drawable-xxhdpi/ic_action_done_dark.png deleted file mode 100644 index 68c41deccb550fc809319aa8efb46f392c6281c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 619 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGok|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n0P&1978H@y_s{+_ppJ8!{n}P_Jl^g15&Add<^BctYsTm z4>5e_GDLs#>D%YM3-mt2b-{ zQReav(feL9Xr3^aRuKKE#=J!3eoVuaC$qUGEUGbP44Rs+eFZc*?GRW@Ar0{5NQ)mVA*nb!T+$r)Oc&qeP0Zskz@Y3FJFO#+uE1vLFh(0+Ks$ZMkfmrxfS zP1Te9QVMNzE_s!9pjCjHI8;qcJzn3vHZ_l!SQ3-SwA=Ftc~CDzuKzYpZh%^ z^;pvS#m=#u;d_4ln7V&*@>UiOiG?LUyV*Zrda4p1AWHC^m8a)MB(z5>b!WJ^Un6l^l sf0mUm#gi8ZJe2&25@A5j&dXL>W2A$!YSA2~)w76%4K0S5*a0S5fcdD8Rv zceE*+xnB=)Yj?TB;6H(ZLxCZ%&M`j0O9;PKB(w9LEqJYWi4o`^fwP(i7(N^q{1!7k Q^CifIp00i_>zopr0M9i`&Hw-a diff --git a/Clover/app/src/main/res/drawable-xxhdpi/ic_action_play.png b/Clover/app/src/main/res/drawable-xxhdpi/ic_action_play.png deleted file mode 100644 index 7f7ca2e028450694d6b4b784bdbdc8552080a46d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 702 zcmV;v0zv(WP)C;$pb0l_222&5>$VaH?7dy=ow$S-Tpenpu~00000 z00000007{hY`5D(x?n5dUg{DNewZX$ zoa3iYu%jQ2y-SR*+)tHv7lk*=-D z;hAS;EQN@@ljF08h`p2ZFObIGZetDa0u+rk+{NBe1Ss=~v)DVD0L4x09aVtt2aPpm z2(Z1jHXD2QAVB$wy%AtLmNeFwBfyRvYuvODd-p2f`+hKuy?Yn%eLtAQ8VLBgAFBVF z4*|RPL$%l&0sHsE=&?5fen(^PGX&V~hf#jbhX7*^Xu+S@NZn1R(`N+KXDKyE^EW&J zby-VYOXJ@dL3MeTT1ey9?11`nK98CuOSnESQnzExc?9gA^SSY_Ttn;6`P}#w?*aAa z{8Ab}@FHe2=ZCScl?d29=Z9L?N(5Ah4-oJ>Lz(rP)(;v@z^Z)f-@F_+ih$R0tz3IM zxOV|2@c{xp88s$G!2WCHwWm2BML^Y<7y%8(2R#Wei-~&|U>+0qDxjH|xHkcta;;oO z9yhHDXfh`5L4e!%z`Fn!F>zD@ZerqS0#*}eF>w?DA>#uN0^G;Mo&|)6iCw}!qXPf{ k000000002MZaxGU0AWNaUcsk$JOBUy07*qoM6N<$g7ES&*Z=?k diff --git a/Clover/app/src/main/res/drawable-xxhdpi/ic_action_refresh.png b/Clover/app/src/main/res/drawable-xxhdpi/ic_action_refresh.png deleted file mode 100644 index 72128fe69086bd90233bd2f16ca25cd52f423326..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 875 zcmV-x1C;!UP)004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00002VoOIv0RM-N%)bBt010qN zS#tmY3ljhU3ljkVnw%H_00QGlL_t(&-tE~>NRwe4!0}CTo{HE;x%AM%xu62Y4l4=5 zL)5J>sA)kGC5fenLhzE>F|ZsdL3A_fP}i9R5)?rwRM%VObYIzLi4$aA zihqXFZWXpZqu8**g`zoKtYlnHjrybG@8@_{Ip!(53P$agM%M4?utis$x-&H*Dp zk8kE-)f!b=q{JT%hI7$0*Sxmp~@O40KeOUgyh7>7%-wczKq z66Ym5OSRWg$yI5pEZi39rJ}T(FFuBgtmZFq1JB0n26^b_)jEaWHD1u2f6Y^>?Wt{? z004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00002VoOIv0RM-N%)bBt010qN zS#tmY3ljhU3ljkVnw%H_00Cl2L_t(&-tF44Q3Npz1<<{O+ie6w+F_`LA_y1)>M(F@ zO#~1?`U#kuIaph^bo=EEBsK76Y)e1zfMHub1SmiO3J|Mz*lhZa0*QNMcNNm!|5D4O2OrRct47kN2WY~KcU(7- zKKP*H%W5Otvq7g1y-rHF;DY|o9hsE!i;V+3LDM_hlo%l72 z)~p-k2OM zh|bZ0bev}kM+0)Dtspl}8_1E<0&?ZlK_d>HoEpfTBZG9Dmo+#Ns0*hI>clC5 zx^eQLj+{KGBPS2)$T<&0;G6@ZaO|L04#x_jacm$W#{!~q^dK@v3!-y$AP0^H8e{3OJ=D11ckd3Zh1^-6VD8O>U1k~=L9}UQ7cy$ c7njZK9T6eN&ustl8t4iJPgg&ebxsLQ0IgI(ivR!s literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-xxhdpi/ic_arrow_back_white_24dp.png b/Clover/app/src/main/res/drawable-xxhdpi/ic_arrow_back_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..746d77579c75aea77bcfc5899ae6d4d280a6db85 GIT binary patch literal 188 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhawnmt_{Lo)8Yy?mOt!9ajHFx-Ll zg68}$oL7?cWR&_eIJ9T2eBk+dYDY(h$E0p=vEyYtFP|-$pykK(^5DjD{>V9kd@>dV z4-PakFVFTne8@uI;eJsS!_m1q1y>sL`B$o6V&n`mzQn>ABz%bz#G2qb>ubGeW}usS iW~iUuJr^LDq<5?Lg};vF*~>uZFnGH9xvXI(3)EF2VS{N990fib~ zFff!FFfhDIU|_JC!N4G1FlSew4N!t9$=lt9;eUJonf*W>XMsm#F#`j)FbFd;%$g&? zz`)q*>EalYaqsPATW_a8nd2YVONv)DEb>%}VqPv~Qp0*x;-Oex(u5WINA=vAf-i=+ z1PknKkUO$cDI-T9izCL#1Qf>q?#tL2J z(Gm<|44rX_XO+=9rmP45XRbbwVSj8nQ&W0MtbWqw!x24Jt+*yJ58>oRxlej)edP8steuc{wdk|h^OT)0BcB0C;p2OR}dNszopr023a^oB#j- diff --git a/Clover/app/src/main/res/drawable-xxhdpi/ic_bookmark_filled.png b/Clover/app/src/main/res/drawable-xxhdpi/ic_bookmark_filled.png deleted file mode 100644 index abda33a90812469fba8103512a8b1149271fa52d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 419 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhaw6p}rHd>I(3)EF2VS{N990fib~ zFff!FFfhDIU|_JC!N4G1FlSew4N!t9$=lt9;eUJonf*W>XMsm#F#`j)FbFd;%$g&? zz`!W&>EalYaqsO7!z?C8k@k=Nt-3BA+LldI#k4G)_!6eaDJtyj61u>=#4BsPfY3&- zqSl78GRNMFPP02C&G#&SedvGbW`i^NKhtKPU1PESB!|ib2d1SAA{U>u39%lwG`6c) zaQqD4t`vuxFTdX3`Rp=VSH;3d5l?!xin(7*tA6fXe(qtlSNsKzB>!pYA0@Q z*mv@0{Y|k8lh!yeae|GL`XYQ!4`?okm(Fi>?7ea$i;#x`kkH6oVCi4dXvVu}iDUAw zFEew(U877i)mWu2J)L;;+~p3o+^prSxk|juzq1+}&Mmk<(dl!zgZqVl9t&@ZUtle< z5ZcH*%kiV~QSJ<;z5lE)J!~lDe(^*ZWYv@}YZzTFuV$3LuMrIlI|ffzKbLh*2~7Y@ Chn=PX diff --git a/Clover/app/src/main/res/drawable-xxhdpi/ic_bookmark_outline_white_24dp.png b/Clover/app/src/main/res/drawable-xxhdpi/ic_bookmark_outline_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..6ed27a24f4dae1f67a8fa7c2616978235c4e9feb GIT binary patch literal 370 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXoKNz-Z~|;uuoF`1a;TPv=09V;{K> zs=vIXdCX4QL+t|V8zToU!Q7zi<=ih=G>shH1ez9UEV-`L+ms;SY*HW0v1~_0&79vg zZ2SI4K46cpYzp#Pd1vCr^9|xQdkc>$u4Z}7bS<~QdDXiW)sB+am%N#FhW(auDZAYT z)|I=zG|uz9yPE&Yx$=XB+&>-UnK)G@I52T;d9q+8kOHxFEjb!lgfz;SLT}8Ce_G#= zRZ_w5U>@JrB1hhHlACYLFqV4SQ1-%D`C5N>w_9WM|GGu35tZGNQODz9g^ zKt82M#J1Rh|Ad5Q*|!Eyhi@L=8dd^HOZJk+HxobczhIbJ0CrvKef1j;i-e;jOI85G OlEKr}&t;ucLK6Vy2ATQ* literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-xxhdpi/ic_bookmark_white_24dp.png b/Clover/app/src/main/res/drawable-xxhdpi/ic_bookmark_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..3faff90bb2b05245359ab9bc9ac54d7e7838f369 GIT binary patch literal 273 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhawZg{#lhGg7(d(n}rDL|w(QT?V+ z*RA&1g`9$0o1=QNIhSZ;3HvoG2(8*5DR47*=X4i~|2KaB_~0@z$ZO>`L1XpjO-rS% zr}5ZY2=i5xCT0D%uC}ojy6s@RC;EniboqsAY*xFQ*O^_oE8D{RMZiO$kwwU3!Mx^q zOq?nc9GEz-6bnFEK<<pF literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-xxhdpi/ic_create_white_24dp.png b/Clover/app/src/main/res/drawable-xxhdpi/ic_create_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..02e19d04570c6f86c7885615cbc9a271a7a04873 GIT binary patch literal 302 zcmV+}0nz@6P)Nklp%{z$v^{5pMgUJ9P141uEYB)_=4RF_CjEcv6+Mn znIBAnGv0XNgxmvXi5r?~6rMQtq!!1P)XA|U^>VC8*ddh(X+J>9y^)Suv$GbGo?4@P z$3{eY=xvsabkJP%VN!{O?z@vFl@sq+=QG$(GU4=-%sAbo$vH)W(#MY3BegB1ZSKdK$X(b(iukxii#&) zXB+`2Dj&R^aRxxq;yb_>Cjp8^Kc>z&j4?L%KF;(Ssh;`jUH||907*qoM6N<$f)^cq A)Bpeg literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-xxhdpi/ic_done_black_24dp.png b/Clover/app/src/main/res/drawable-xxhdpi/ic_done_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..c9c017410928bb4c9ee56d705130377537886c81 GIT binary patch literal 227 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhawR(ZNOhEy=Vy}Xh4P=JVY;Pow> z)eh4Z*LH7YPT^1c;c>xMY3CR5UF8g~O~MqEfWRtq)wx@t#f5EcS$cj=DHe>A9+n8m zSQI=s(8$bw&b3_ExG+wt$|R_#_-}!m@==T1(=U4%_LXEm_Sb!xepO%dfZ-C;lZ8td zj!$Hgapx-N^Vofj<@f|98RxE|K99&g#i>rA^B#LHEf9Sw5tKPe>yY6RAwfaGi}hdF Y%FU*83Z;v716|GF>FVdQ&MBb@0A~SHegFUf literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-xxhdpi/ic_done_white_24dp.png b/Clover/app/src/main/res/drawable-xxhdpi/ic_done_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..0ebb55559b55f99df3270796763745a71f113078 GIT binary patch literal 255 zcmV=}0*5fKp)HP1G&I6Iqc zjKz5rgEVtukiIy2Qo_-K;J|?c2M!!K@i?}(lWik$uJ;4aeo|e|;mI*SsV?U@bDX5g zSJ{Te;g>S0!OODIPipkgGo)TTcRZxVWAGnIFqKOr(UM3=(~BhBSvit;g=R?Vjh>M7 zAB+M?!6}eboF615Cqq(m7NiKA4^kA)n-qydL_|cirW>R3em?os7vTT^002ovPDHLk FV1hF8Y9jyu literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-xxhdpi/ic_drawer.png b/Clover/app/src/main/res/drawable-xxhdpi/ic_drawer.png deleted file mode 100644 index f7e3b3079dc64a11586da568e608a9c4b81e3598..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 202 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC&H|6fVg?3oVGw3ym^DWND5#L^ z5#-Cjkf+YTP`sXjk!=$LL!~YQgWnqlM%L3n1JW26goK+9UQq_B4e)ev49U3n_WDL% z1_d7GgKPMNif1co2rbdBYgqj#WYVvlObit)YichE0u?hHkZ|w@(Lk_G07N!;^MELZ e2g=MKDuXFT&eXtIQEbyC5ZBYy&t;ucLK6UHCM?MS diff --git a/Clover/app/src/main/res/drawable-xxhdpi/ic_more.png b/Clover/app/src/main/res/drawable-xxhdpi/ic_more.png deleted file mode 100644 index 2955c02ecd66deb2349ba92839bb00afbfb3791d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 313 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhaw6p}rHd>I(3)EF2VS{N990fib~ zFff!FFfhDIU|_JC!N4G1FlSew4N!t9$=lt9;eUJonf*W>XMsm#F#`j)FbFd;%$g$s z6x`_P;uw-~@9i~ju4V@ThKn~{-wT`+bp1H3PE5)2)Pr@KI9d|Y#67rIzT>uGYg^}H zbzRM|iG@>0<;C>{vl?6H&Yd|=ORD7Yx!*Y^6BqnCP&rAja6#jxlEMW`Ic7a_s1}^U zy0=WP>6k@8Jj>R?1zm5OH@nsSb}3d^8?)Ho-SxPOn(?K&?^bcuj!iml-4~NgE`X^o wx44B;45NC)79Y(3Q^!LmC;;vKYyE=p+>yE$dwEZ00v*rb>FVdQ&MBb@02ESj-%nby>)6J_QWKRvd(S?`Ri~_DWys(>8rgyQv zG%aCaz>Js9>y=L)eUVgRxJx3oN6$@sv5NTO?u&4dNh*K$SbOB%sZae;9uIUXgQu&X J%Q~loCIECSTxI|O literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-xxhdpi/ic_refresh_white_24dp.png b/Clover/app/src/main/res/drawable-xxhdpi/ic_refresh_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..1692d8a242162dc878d42fb1b112e918cc25c3ac GIT binary patch literal 734 zcmV<40wMj0P)}R?1pi{*}C8ro5mjO-_Ru*)DiiH)#7^4tLdZA<=>SdMkpq|I%AXn6pz$;0s3PKrYm?8_gA;c@ZhG~!mn)t?F z$qgNN4O1ga+~BX|f)yk&k~GK?-DDvb#PDjBCA!H<_NZhGqgR%Ql7sAV3M0iTSs_YJ zvc~|%OAhJatMnt8@AV$4Pk2pqH zrN<;jNTtUlMo6Vc93!mKV-TZWrAHq|M5RX$##I#o*D*R}iwMSB`9>KZFt*DURd{Wb zPi)1Qpj`HNj&VyqaS!9ZTyPR2MXh{b9chdMazO=2j0bW?8T}X|ER-8A;dMxkIDywW zxnddLF~(Rg2W(;jBhDhZqaCl0)X5U-7{TkX{9pku@%qFDS)h^6cs-&_{!mK-uW^p3 zK(sNA*C&?CKX#F3riZLn9;~6CnI>pbad4E`Qru>b~1{qINMZw)bIiqPg$vdg9V)BJ2t*?ntA${sOADm3Ngxg zD)c{4!Ev53O*Yd!;W*{`zgWT^F4D^zJ~P22UwF-ZF0h-W3IqayKw!@L0j`rmsrdc? QM*si-07*qoM6N<$f&f-ZIRF3v literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-xxhdpi/panel_shadow.9.png b/Clover/app/src/main/res/drawable-xxhdpi/panel_shadow.9.png deleted file mode 100644 index 82091c3b6e6b33e157fd4a2108d3549cd22aa918..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 144 zcmeAS@N?(olHy`uVBq!ia0vp^F+j}0!3HEtKFrt&q{2O2978H@y}f45=ingX_V6Q@ zlG72Xw!irkCQC?h@m~EodHv3(EAu#xo7Fzsc6{;fX{wf8OI%u|c%w>Q7$zKPkrd>< twt4G8-n@cl={pbD>Lu@N|8QKqkez+vA*0BCQD2}H44$rjF6*2UngCeEG?M@T diff --git a/Clover/app/src/main/res/drawable-xxhdpi/progress_primary_holo_light.9.png b/Clover/app/src/main/res/drawable-xxhdpi/progress_primary_holo_light.9.png deleted file mode 100644 index add4d383807610148174bfc3d99ac9a72e281f62..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3029 zcmbVOc|25m8=taoWxJxpH15TvF>}V4F_Wb+Lo>1^YbwUf!Ne@)42H5t6j>8eTuWJ7 zl(Kb&db9Kta^Lrl`?-I-=lPuT+n(?DS$@y+`J7Z2ryWZ28|7gz zm=cXjaTSjg@r#j_7Jpv{MRUZ1mcZ6au$vnoh@kU97>UXC2jMg}JrHyS>CDK`ZqNb- zlL%nBc?rB69f%Ar+l0QVV5d z^2lHiiyFlTcSkw7F`|MQ1SZ1T3T`1JiV4`DfDRY3LpTsoXo>jBOBBynw^0cAR~139 zCE}Y?UXCtsGM5j+%}mfp1{#Nk;{X%D6pP2>x56=K0F6RpPyhxA;EARfA{q_<{vgEG z_{;#JE5+`+E%C|{5hM`sh$vJ0h06$IgB$^kVu=u+ zm@rvPqAfr+$70ENJOzWsnFD}19# zad~j^ZZo(eox$R)u2-+;TeK9A&k6^bc6=@y{x!cu*5BACknC_2tPS2A{XK4TGLAsN z;KU^b*pkoy;yaf4|KtoMb_TUt9RE`+KeogbxH|o-^u>$6ng`^FJBBZAjiwFtw_q?? zDH?_3CVcYFrXub6vvf&o(e&}wS%W@^}>K;qwH;k#(_gHr=q#a7c zd4qNPa4MPU*U^&XHIfpTvNxpEyYy9MadKD()IUKR#gdO>`*K<>V^Ua{X5($b~~kjnoTvf4Zv2FLqBB zW{#$FL~p>#W&_;w$12bTdSO#|{Ub~;tTUM=8mSS))^X|dH<(4mY zmf5{Ebm>r5e_NT;!A>1ehBJRs^u#H4z2qnDt`9Q9iE;%>!Xvj0Z~GamM(rDkNzs2I zjaaz4_U%*27k^|Pv%C3PxsoLx^Xvuh^zl9~-?d9U@+W2%6Y@@0Z3a$}iXFEO1$a74 zg*Rq&U+}{D(33mN4Nip7{A*R&IW+Lh&jk~01YpsaTW25@_wKY@0la<3(?p#LC?W$N zy>Y!yTcWIlpx@~;9=0hCQT@7#8D&?ls&d}+jjr#~sj#%rDAnz!sJun{_igsS?$N1~ ze4}leC*h>9Zc$_0tG!5bOULgwRO6y+j@~nnzs!zPe0n1d%Enx>-xgf=aH`QIQP@y! z;TaiT?c3k{o31y?p-YBRtHuql8E+IlmU*8$(Gq6#CGy6CW>s2l%w+qy6b#Iou%T8N zRN^hnZl#zbmFauV*0-u#HQUQ&Ntc*Ak9Q=p{e2JKKuC2Jg&O0|sykr`HZ!ABjqUgA zWtr5rV)S-})btU}JL^SoM17tD+0IC#*+Fsq7p0?Tqg{s(k75@;)U*%#w!j$*%)@`o z2&xsk^5!G)BO`+F)!Y3ke-6sGEV;TACL0=ADBz5|cN!P& zTnB}uxNhi>;2ciD=Od&YlE(GbG|)C0R1Hk#%hYTb=kOL~1S4-9BZT++396j-<-udN z_Ox4@-YaM@zLmt4uU?WQ#AzzvhC3MRbc>Rv!@I>8RZ z2w!*X{N}dsH48I%?JE;85A*YhF&`}eMp|H+D6otWyLdHvPsz%WzU5`zm`^7cJ*qiO zYo}qMhb=%1nDLfvu7VF$we8pq{iX#$*8MB%o)%jNOiYhCyt_&h-I}YAI=?SBH0K$zOwzgFY}3{1ITn51=hgme=_vaLEg2-)zQ~nulEdY`kYn@(&yr%|zceyA zWpjhoB&DX@utqn_-07(jpX^4}pp6yVcIAvv534@c)F8F_iGH=oFnSO~k2ZU<-RzkC z;QVC6y)O#~iWor~QE^>wH{~u>`jt&4868@7aw7lh1nz#*U~W@|pu|1z`a-9tK}77- zw9|=c5viGc4`fmFFn8wVdidQFnQ5wsyJr)2rr@MLRl7-_cE89jne>3e+`}j2`!B*b z6#wR|=@~Dr)e|P;s`<#KZFJ1=RvjgE-9@Q5eI11T5;YlPJzM@c_8#_yoTOGNV{3ZC znReqxr3*VwOjBxyYz({Z8za=Z^O|xPIFA-`#oM}~Yv&dbz6EYg&OVR4{qGv<>KX1; z9#~UZx;i!{E)<0rto; z$;WgFl~SV2gV5I%!iLcsXWFXNXd1zHhdyja-J1U};T|d3a4>d$#^)ley087SR-x7N z6-^&lx}o;^fb~?P_nIno*{OX(ElQ-Qb8qSk_7#g=1=rR{Bccxj%4V|!MV*S0xZWaT zV_3PAkKdd4l8iJ}y^dC-@_II`G{02_9-4d%C}Dax*9RHiJ?W7>V)(W?QP6j9PE>P5 zi!zY+A_|l^ekePO_G)nn8DH7+)4=T`YB6$_btaw$aGCN6g|XY6wV0FRAtOI2KOBEp za`cLpmfab6Y|@n z2OmCxrq0hNMPk)8g05uJtNLm$(B_T{|81Rcj(kBqyA$i2-@I@3W+Xok6&<_ZJH=|$ zA~YjqPr)_yOR^Qu?OMx!#$CO+C#(1XG$k-kRqhd8fna2d~FRHzd^#wZGfH zpsToia_^j!LP4>~lkk8dsIzzYQ2Li!yv>`gFXNJLrvHBYvp#giddbKi8c22tr7A_} zWfq^w%ozEzPcJ0Bb*v** zEM1AR1#_3DiR4KSHP^2)%hTdLjfF4VFI;h-in^Ijk!2G`w%osZ4) zB$G9|i_H5lGw-tRf>Hng001%BO0sjURx9Yup>DD*623&d=r+-9q}xNc+kM)oBrWHQ z-h4;QMj7fBYFRI9OVWZ4=7M&K>&BVscB@5AqITMeA?W8v`$1~th5s!Gg2ylnpWoYQ zJH`|T*^BxSwZnGA-FKHUSEbyMvCdr?3p$;S5kW?$ zJCP(E%LCF6=}#`#q&$c+EyzmZ;Ik+jf{d+6t3-{*V|8|RruO#soR>45PF1_zws!NG zwG>=BERrMut_zaqY4h$ttLI6Q9l0!OA;?q~=j_R>tD;;H~%?398r0=Wbb|5U6iQ26u;!6IC7P!JXI&H{I0$r2#$Q~NWb6zpS2wyAFIpDOLcX1 z<)e>T7>0k}{xb7I6e%<*m&-KFX@HQxG!l!XsqxriKG$nvce>Z zqzB?p*Xc rx)q3Zs*y8!FN*^J003BwEotX#V0hoD#rW;IN7}^1dx*!o0vGkq_P=?^*zw2xBebSW) zTw{Db&b=qLvEu*$003ObO_0v5R;#2J54y>+O!xw^*KMQQQn%G)GI@zrl9uyHFTNrs zRu;N>TGl?YBrWLvAn1;`#?DT+CoO8@*Xi~GLErz^4?-hf{4cKSK6{?`dajeYV2Fd{ zMSb(@pnP6qh%-k?C&gnRNrx(qBEc-RpqcbQ%*+pahZ^8wNhM;I3gsY@80u1*n}QY& zUGXqEy}mXDl^IDAU@57?3X1!EkaQ*k zbINp4iG zXzg~pPL?>Ho}bU>Np5E6dEW2TGfBRcS-tF7K6e_~udZp>$m%ey5M;k7BiG%@F|qY} z9m_8eBtTKlE6JQ9SJlR~UyH>eAChE8;@TNGwiZQ_2r}_=mE0Y103;y^kOW9V5+Dgl zfFwW?k^o77BqRZnkOW8qBq0fq1V};>APJC!BtR09z$P+xqukMGODGLdsqSQ@9kDYr7wN?K66RGBY z91`LzH5Z&=y(sHeBG#cYXLGKK0{{R3h|FIB Z1^@>L@$&l2E-L^4002ovPDHLkV1kmljYR+e diff --git a/Clover/app/src/main/res/drawable-xxxhdpi/ic_action_refresh.png b/Clover/app/src/main/res/drawable-xxxhdpi/ic_action_refresh.png deleted file mode 100644 index d271d8e03f41181bc2ee2c26762a11597ca486ce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1148 zcmV-?1cUpDP)004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00002VoOIv0RM-N%)bBt010qN zS#tmY3ljhU3ljkVnw%H_00Z<%L_t(|+U=TeNS#$2$M3zGqNy_{Ehs`}tygo=h7qGz zTgG09vD#iO3ihTKU8nAafz+mwnnmGQAvHEC{}jZ8jScoksFgd%gF0e$R0aoO9k?p8GxD&%Nh4=RCjX8zB!&24 z{Qv=8<4>g860an%9}qwWCy;LM-kVCz%I5(9WYd?_$`swisi2f1vdAExQua{8SIi{+ zUKg2~{Qv;6xR}tw93AXTx>xL`lUoVD|C8Y}VSpHC6AV5YG z?$SbTS~{EglvVoxuNsFKrOeY(u$L*j08bis+;7P9yc9pe6?*_NzBkB!Ow89_p2K-t z0B;z?KM^OgW~q};^lzUJrJQ<`)%69 z0rb~~hvWcqnN!4<*&%9wx3<V-!G`{#e4a4kQJ3NwDUaHO zv5!;1rxr6gm#_>t&q>OS39Ntc%Q=}O}VINOWOg0a&iEX?< z9X*D<&*HxKb_j4 zImqB^A;(zoWPX7LAG^3{^f-??hSM@XOx(YDIe@kP3?K00x004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00002VoOIv0RM-N%)bBt010qN zS#tmY3ljhU3ljkVnw%H_00HnxL_t(|+U?slARa_F-oSNFV*CRE zFX3I(y*p1(!2`H*C5($MikM{Hn|YJpZ)9G#oyqspgftY|1*v=X&;bpA4rl;$Km(uy z8UP*80O)}K16a$Oe9MPC$dPGX;CKyTH!oqOUx^O?n{Onb)5r2n1a$m(zJb7+uO{&3 zD+$c`DgrM5QjxD9u%Ce_0ST}W4yX3mzehekJj;QcE8cf1ojkETN}ME}g$>IkG=%qX zmO%L80BloJ2(Ju)U8bFIg$Mjjv=OeS_r>Jf2>sm7sC+%4pWhpouOsxa-I4imLNvcT zAbx|KCMfbt19acA;{;WHS%CIYZH#cCJqknqH~|c>2mc`Dp;6{1gCHz8yf8Zw1ih+W>_5764_w9zdF}1?1%4mdw`yi1Rf7 z>ijr>JU<4Y&z}cWkUs~gB7Y80MScmuqWS)Sh4Z}ui|6|S?v~H@1VHlr0HAy?04(1J z0L=FQK=bnf;QU+wJUsf$WI55UmyYGA&u SvK4y(0000vEW~>Yh8z!zhcP@Va>lc6Sa89-tPWqhgl<@D4srCO* z^`HMI=*RD?`T6PT>FH3$`{I{BwQcL4K9$~ZkVSrDy2(TLv?flq86WJM_Og59@$VW$<+M Kb6Mw<&;$U`CtAt? literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-xxxhdpi/ic_arrow_back_white_24dp.png b/Clover/app/src/main/res/drawable-xxxhdpi/ic_arrow_back_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..fb06e1d485ce129cab833f240d21ed991946ab2a GIT binary patch literal 231 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%xcg)_J-(hE&{od-bH?Ap-%|gPaUS zEjAHTqy?sL$k!8hmo#=RXZatR*$Gs7!zF+3(|PvUJD;cfMw~f6W5cZZx(^TkxoP?R zkGuVh{Cz*4%|<2oXZ>eA`JA8gM)ALfhT7-c8U-y}F^`zeXEgTvG_i30pYUOdf}_*i zmc=ZbLRl(%R6HgqJWLnz6PzimH}SOAL#dxSLPqD}RqiOQ*L)}kbinKi=5P5+>+&lV Q%YZxvPgg&ebxsLQ0E*RKGXMYp literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-xxxhdpi/ic_bookmark.png b/Clover/app/src/main/res/drawable-xxxhdpi/ic_bookmark.png deleted file mode 100644 index c987a705973eaed367ca5ab74c83a9492776ab3c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 659 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%xcg6p}rHd>I(3)EF2VS{N990fib~ zFff!FFfhDIU|_JC!N4G1FlSew4N!t9$=lt9;eUJonf*W>XMsm#F#`j)FbFd;%$g$s zRKe}(;uunK>+S8;{?3LHtRITSB@Ukv^hhgIvEiBdSdfK}C#&j##}94?Ma7v9CpJVi zIVerwE}G<{c!9$p;aF-SyR%0^&UV?{of9tKy0>lrmz>yX@7<2v&y(a(XkcIh6D%w~ zj~UE69FN-`_A@u%Xm0vpI_t3NGv+0axK3Am6I{4g;WqoT z4f%FA{;;TBa1ePh+4IbUTVFZXu-~>5NW5FyBGy!At+%WHg7POuM#G{sX7--tGOsMs zuJ3%mbyhQnt4HePd__hU0fz<$hP%vQ7wlp$VZy`6yVY?0ruzoQ2OQt!t{dpR`xTWn z&7^M9@|;O3vuz%xJgSH~_y1lkgHcTC+GJ* zo&IYIY-$@+<33#7vE$QJ@fa@N7uyaPoX+_Ys(dS9=HdO^8U@q&?X^m3ALw!KXV&=C zqpN;(m+ricH}nted2#+<>t^vei|7D?UuhjzL6-eNVjbM&QY3Q zI?dw7$C_!X*DmvQL_W+z8^9x^Ir8RPK{jf9HTUE4xiE)zi<@^Oq3}>7# z`!BFze&d`ht&!g_zx9|+KpaD!Q?i)GbB65;J^7}zZ=dmHdlxj0I6mBG$oK3vImGTL S^$wU;7(8A5T-G@yGywqPtOOkZ diff --git a/Clover/app/src/main/res/drawable-xxxhdpi/ic_bookmark_filled.png b/Clover/app/src/main/res/drawable-xxxhdpi/ic_bookmark_filled.png deleted file mode 100644 index 325c7b2f56330f32ec02f51d643a875b7df365aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 517 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%xcg6p}rHd>I(3)EF2VS{N990fib~ zFff!FFfhDIU|_JC!N4G1FlSew4N!t9$=lt9;eUJonf*W>XMsm#F#`j)FbFd;%$g&? zz`$7R>EaktaqI1^{a%LyB-%cz|64h8j`glCj$Kzm=j>^`*BIc+aj#3(>x0l2raLU| zyH|EEUfh?LyXuqG!LMv5GB9x{G=K@!gmyXhoC}}+ zs7Ri_GoeUcNZ|7G4vh!gbBhj2E;eYGk^PN#)sCkZ<_54BJUF89=E`5ccMZC7&Bu(T zFRgpM{Q;kay5XOlJQiPhD-v!Cd^oZ!|A6%Cwg$tE`3E{oZ;PHXPk2-NQpkaUkwsvE zUqeqQkOp$3cxG%+0^9G<%=li18|;<~2?yA{A?`Af_>j5nsxwHJLxUF6n(aTh6c{AK zzcjYwb=Hdg=c!OsefstJinE5cw@Mj#UKXExa{Z=QtdP}Jwi#WAFU@$Dr;ZlOYn;~$+h z&K>pTin+^_%N5^H{r22GhVKj1zPA`P&0>jf&_57%UFOiin@3f}_n!IvOeDpl|LdLm z*6+U8Ui)2K^FaJ&u$Si2DM2==XS!J43x)M$3g0c;UMu&xaf*(2rT-jJg*3koJK=QZ z3ilPqA{pjQ5Lz{5oBab`#p>7mKb%hN`^CIZa8tAWg9Gnf&y~-#RuFVxU}Ownk!1ke6q+;zqx@$HeGJcfps?4iGOeomkEW#v8b3kfHt{m(o- z;aDw$>@t~;FHTJHvuN1c!g>Cjx#GcqeGJlZA75O*eSA+^u*`ubIsShY|0l?G|7O-% z+_`RkZNNW<#~D27Qd8^?7)TwKWD^xhkm#)pc*uC|q6C|$T!K81!^pt5cq9KQ`3GiF umlynDT({Ve=M;~|3r>(P!Ctkv<1b~Px_n0j<4<5*F?hQAxvXnA9J9H`$wr0 zZy3HcXmp(|G2Fn)!sA#jpO9_1M0>@t(jPOJxtvd=PO>&Pc|RxnzVQAh`+roY0l_g# z+i12;(l;(`PBDDD%=Z0`^ptaM?_NA(DzOQ;sC?I^A$rxT=L~ZUgRY)1k}vR0HUHV5 zu2p@GeNVtmJNXUEx6~ZCVB*lgz{te1$Bb7%0mRJrWoF?3G7nT=28nYBe7Fcz(gT%o zC}muWsi>^BNep8S44c-;+IzJ$YFi{=0KM{fM7-jHC@eP3T9gi}Gnx8UFc zErx>`P26mu{2lJX{Hx>)Doq|Pc*S_xU6^kbmq5Q-dcec(kJQ4;w e1!%j*4u4672{qE|*LeX0j=|H_&t;ucLK6V3Jc9`U literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-xxxhdpi/ic_create_white_24dp.png b/Clover/app/src/main/res/drawable-xxxhdpi/ic_create_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..d6668a051cd53b2ef454e8e09872339348c2ee22 GIT binary patch literal 355 zcmV-p0i6DcP)o)4CwERtj4{R- zW9;vcYqq-8KB2^1t{_z z0h;{m09AfwfG$5PK$)Krpv|uhQ0Fto7-NhzVt3qk;nT+k=6L`B002ovPDHLkV1hVj BpML-V literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-xxxhdpi/ic_done_black_24dp.png b/Clover/app/src/main/res/drawable-xxxhdpi/ic_done_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..2f6d6386de9510fa6dd8c83cbb61a6f2e0fab9b2 GIT binary patch literal 277 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%xcg?s&R5hEy=VJ?|UH<|x2&QEUS@ zUqF*g%NA{xn*DVG1~S@B-uDxXPUtYNKXnEQ>b^wD=lt6oW;%QS1o1=daUAyI8~(&3 zd|u96v#;i-{{JTZcp&}h>FMeJ8GvN{`tw#N{;ZEGUD<;p)-Lh7=#>`kZ6pLOOe=>Nw L`njxgN@xNAv*3Ko literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-xxxhdpi/ic_done_white_24dp.png b/Clover/app/src/main/res/drawable-xxxhdpi/ic_done_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..d670618c7e96225f7756cb4c2743e7ebbf688cf8 GIT binary patch literal 308 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%xcgetWt&hE&{od;P3vlYxj!B3Hnh z1714EonD+``t$ZU)3IJ|2aboi6~%ilJM7!-={Kv*@R&q$518Ox)_m^XpXp1^&DOu% zB6r^~@kqJ%j0e`LXFkL-JviL|Ir_(khlktwLa#r83bn@|VwIw^gKjzH(>hUq>tlAsh9~)aj{(R+p z`Qx=v&?j!r?}<)Pb+Jxa|B9Td>MRd7#ru4CATBh=u6rtHI(3)EF2VS{N990fib~ zFff!FFfhDIU|_JC!N4G1FlSew4N!t9$=lt9;eUJonf*W>XMsm#F#`j)FbFd;%$g&? zz`)4p>EaktaqI03N3LcA5!Z`nR&{GWiVB_7n5}uqRb!XX+$W`X7D-B;SpI!?qs)aP zG3x2R3xQ_Afd>Btt&GbHomcOXif)KnyiZ+g#U`c|U$5QtvE;C1SiJ67G{cr%^D6#t zFR)k8Fm?XfpvxI?ie1L@0H1<&f-lpvPmFe)FHW(Wbam!_$$Y4=`<_R&w0hyvmnA>- zZP)xc6Ut?;9~3e_`KM+5a%tYEE!o%Cy!%%^pPLu#fCbzaTVFVpDDD!7WMzo$&~p)A y1QgkE0phw{0#Koep$r$G>S8;fS|LjQGyh=NbH+>|^^#^ONW|0C&t;ucLK6TZw}Sit diff --git a/Clover/app/src/main/res/drawable-xxxhdpi/ic_more_vert_white_24dp.png b/Clover/app/src/main/res/drawable-xxxhdpi/ic_more_vert_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..2f2cb3d004f6e828917b5f6b1decc7fe5d99b445 GIT binary patch literal 305 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%xcget5b#hE&{od&7{g$w9>R;>#mP zB_2gJIy{WxDHIfl;54zZ?(Dj(@bmNJ>M(=pX9D&J05vf@IA0RFIB;_s@2aW4t^P!s z?~T5q@wxa<`?f89Li_gpTlKB*dwsOb9#+$?m6!M>7BklVVk|aEPh1DJ$>V{EJl=XH?V({#-awY-(QL|0?dORlc*XtSl(} z&d3n4k$a}x{MZxU-fiZ-$+m%8aD#C}>V?${Gwe!OwoRt{8X v))3p#FqiR-(={Oe2E;4(u$C!;+}~cs6m#}#(>L)Q#vrbztDnm{r-UW|mL!4d literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-xxxhdpi/ic_refresh_white_24dp.png b/Clover/app/src/main/res/drawable-xxxhdpi/ic_refresh_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..f5beca2511d275c2f754b38989a1e1e69196da05 GIT binary patch literal 967 zcmV;&133JNP)`{$AjijdZyt1MC$Azf957h>3-t3^RKU9_d^!eEr!Ikee|V#8uo zB-PXcagY>r5oi=j5EdwHm3A>)o13%M6gJwvNrd#g?>T4ZywCH_z3_ZKlIMAz=Xsvz zd7dNO!jtqc#7V}u%mNEsW{i^z(ajUwq>|97TB%YIXrP0O6iIIJ7P-vPO|?qE^}Nd> zMUYE8MJ~gvR|Gu77)z2n+|Ddvhp16R+{kg3AXiB9En#nymIbOfLP2tc=Lma8*65}n zxj_R{1RWwROJrGs+#pNPFg3D7mLX^Ya$9h>JOA+J(I|=HRB{CF6E-;K~lxkTa zLy=^U`v_{26*3e}_IMrBBvrCN7bTEAPGjnm1-dASY_XQ04T_8|N+ers!!)MI=%i$_ z#coXd6%n08AX^;7)T&76Bof);IHt`?7S3X7QnE0OsZq(oB}^4c7XHLkp=9A4rbZ)udzg;N1$r<|QLPwI z&n%`FHnD(d zlnS{+2SFp$$Prd^hM?!=5_OCdbeOappo}jG`i)AtMGIjAvPO!J2-_z2I7-+6X<4A0 zeS{rR99YLi!iK0-MAY*+VH2!XJb08`e&!xUz(#%{Y>_RB4|~XEo?cd|1k}>Y-{i7O zaU#Ws|}!6-dEfx=QHw|VlU04lm{uA*~>Kf43bv-DCc7enc!1)u!Y-L zLnYTy&mBBWI|mr2kbRVCd61$P*Iv=`;xYcfm1(wX`Ee^>XL$g*c*07zI8RR?8GRYkCOf$*} p4w7XnH^}om&+|Ob^E}Uye*phd*siKI(OCch002ovPDHLkV1hNcx5WSe literal 0 HcmV?d00001 diff --git a/Clover/app/src/main/res/drawable-xxxhdpi/skip_arrow_down.png b/Clover/app/src/main/res/drawable-xxxhdpi/skip_arrow_down.png deleted file mode 100644 index 2a3d6b4a004fd7fea5c07166a3d429b78a065d2b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1108 zcmeAS@N?(olHy`uVBq!ia0vp^Js`}%1|-)VaI^zbk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n7?_tIEGZ*dNX&uzp|r9!}b;~r{ZO7%@LcQ&06rj|HiLh zRW|hwwsQT;rQ#cREU{&2>RL1_LFxg^vu6|U-idX3@o&bVJ(c&T`y88M^!wZE+2+Q7 zC#nGL27(XM`_`+U`n>1$uKX4gn`M_@CJP+0@cgyTy3F?%bDr;ooEYK4X?_c)`-?6U zP}O!}thL!ucHL!;A9Lis-Fm9eUR9R9z2>?3R;Ph$@26%fRjZV)U!h+QR-4X~hg^XIFdKYyM>*+W53U;jRn{-+G5W7ZNpWm3{Vqpl02aAtW$ z=}mWJRhuF{>4-~`GjFrWs}#;nFI;C8q;i%`RcVy!KkmqO=GWHuAGMTsyD9dVW^VC0 zdNBV^tvpHtL`rR?j$KEoRw)YDqSUT<4 zw=Yb)yC-&?(xcbCMwNg+oJdLEZ66$myYOo zUpZ9MYO?XP&|ZW2n!T)%Eq{+NJnfxw-tMQ{x#kqp6h|>($!GDIE)w(E>z=;cDH`d+ zsr;knf9KKfGP8w`O*aWkHPrNp&eS=b6gFeorHJWAw-}Tzbrfs)=|8LAWyL3n7DuTR z#~D?@eDORD22+}^&$ zTBeSVV(*DbV!VY@bmyij1}{DERqc$mr2DPL?Amwk6E2@yma%%5Br7CWGVJ;2-oVH( W%}mna+Hvm^kf5ilpUXO@geCw9O4Ww| diff --git a/Clover/app/src/main/res/drawable-xxxhdpi/skip_arrow_up.png b/Clover/app/src/main/res/drawable-xxxhdpi/skip_arrow_up.png deleted file mode 100644 index 81db297e3211121c9e7bca1629c85099b9e5bbee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1089 zcmeAS@N?(olHy`uVBq!ia0vp^Js`}%1|-)VaI^zbk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+m>+w(IEGZ*dUI!^pR^}KL*nKpCdJt1mP<D;mb^5T>$g{DR8zRgZ=QcxEWdoOiRX8bZ5-)R47ER( zCS++eOLgtKzI?;owM^;RtUC2=v-cUkuZchW&2T~G4UQRAy`QF+dX*h@zHfoz8-{qF(esC$L1xQH*a3Tw)Fo0_faoi zmdrY1XKQcIZ2bD$H#1G0-XHzVF(aH~`SRu5@5SFU`#wyVc9e;CnZVh4@%l7H1nsIz z{r5{MAwg3Jr1faS%S)+Kb}j%Ks8(%I_&{Gz&#JPqZ2I@TlM~YRFJ)(EpZiz0_xHW4 z`#o0d>QHSznjHSWXK54btTzXqbSzz+p%t;!>(|x*j^5E4+bFcboFyt=akR{01_+rEdT%j diff --git a/Clover/app/src/main/res/drawable/pin_icon_blue.xml b/Clover/app/src/main/res/drawable/pin_icon_blue.xml deleted file mode 100644 index b52ecf8e..00000000 --- a/Clover/app/src/main/res/drawable/pin_icon_blue.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - diff --git a/Clover/app/src/main/res/drawable/pin_icon_gray.xml b/Clover/app/src/main/res/drawable/pin_icon_gray.xml deleted file mode 100644 index a94592e4..00000000 --- a/Clover/app/src/main/res/drawable/pin_icon_gray.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - diff --git a/Clover/app/src/main/res/drawable/pin_icon_red.xml b/Clover/app/src/main/res/drawable/pin_icon_red.xml deleted file mode 100644 index d3867dc6..00000000 --- a/Clover/app/src/main/res/drawable/pin_icon_red.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - diff --git a/Clover/app/src/main/res/drawable/preference_description_bottom.xml b/Clover/app/src/main/res/drawable/preference_description_bottom.xml deleted file mode 100644 index 856fffa2..00000000 --- a/Clover/app/src/main/res/drawable/preference_description_bottom.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/Clover/app/src/main/res/drawable/preference_description_top.xml b/Clover/app/src/main/res/drawable/preference_description_top.xml deleted file mode 100644 index 1944ff95..00000000 --- a/Clover/app/src/main/res/drawable/preference_description_top.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/Clover/app/src/main/res/drawable/progressbar_no_bg.xml b/Clover/app/src/main/res/drawable/progressbar_no_bg.xml deleted file mode 100644 index 18952ca4..00000000 --- a/Clover/app/src/main/res/drawable/progressbar_no_bg.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - diff --git a/Clover/app/src/main/res/anim/fade_out.xml b/Clover/app/src/main/res/drawable/setting_description_bottom.xml similarity index 79% rename from Clover/app/src/main/res/anim/fade_out.xml rename to Clover/app/src/main/res/drawable/setting_description_bottom.xml index 3994dfc1..5c2cc907 100644 --- a/Clover/app/src/main/res/anim/fade_out.xml +++ b/Clover/app/src/main/res/drawable/setting_description_bottom.xml @@ -15,9 +15,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . --> - - - + + + + diff --git a/Clover/app/src/main/res/anim/fade_in.xml b/Clover/app/src/main/res/drawable/setting_description_top.xml similarity index 79% rename from Clover/app/src/main/res/anim/fade_in.xml rename to Clover/app/src/main/res/drawable/setting_description_top.xml index 9c9c27a0..30e597b3 100644 --- a/Clover/app/src/main/res/anim/fade_in.xml +++ b/Clover/app/src/main/res/drawable/setting_description_top.xml @@ -15,9 +15,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . --> - - - + + + + diff --git a/Clover/app/src/main/res/layout/activity_base.xml b/Clover/app/src/main/res/layout/activity_base.xml deleted file mode 100644 index b88b8375..00000000 --- a/Clover/app/src/main/res/layout/activity_base.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/Clover/app/src/main/res/layout/board_edit_item.xml b/Clover/app/src/main/res/layout/board_edit_item.xml deleted file mode 100644 index 6ca3f76e..00000000 --- a/Clover/app/src/main/res/layout/board_edit_item.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - diff --git a/Clover/app/src/main/res/layout/board_select_add.xml b/Clover/app/src/main/res/layout/board_select_add.xml deleted file mode 100644 index 8cefcd90..00000000 --- a/Clover/app/src/main/res/layout/board_select_add.xml +++ /dev/null @@ -1,30 +0,0 @@ - - diff --git a/Clover/app/src/main/res/layout/board_select_spinner.xml b/Clover/app/src/main/res/layout/board_select_spinner.xml deleted file mode 100644 index 69aa7840..00000000 --- a/Clover/app/src/main/res/layout/board_select_spinner.xml +++ /dev/null @@ -1,29 +0,0 @@ - - diff --git a/Clover/app/src/main/res/layout/board_select_spinner_dropdown.xml b/Clover/app/src/main/res/layout/board_select_spinner_dropdown.xml deleted file mode 100644 index 525e726e..00000000 --- a/Clover/app/src/main/res/layout/board_select_spinner_dropdown.xml +++ /dev/null @@ -1,29 +0,0 @@ - - diff --git a/Clover/app/src/main/res/layout/cell_board_edit.xml b/Clover/app/src/main/res/layout/cell_board_edit.xml index f5b1d475..98eb674c 100644 --- a/Clover/app/src/main/res/layout/cell_board_edit.xml +++ b/Clover/app/src/main/res/layout/cell_board_edit.xml @@ -1,18 +1,36 @@ - + + android:background="?attr/selectableItemBackground" + android:orientation="horizontal"> + tools:ignore="ContentDescription" /> + + android:background="?attr/selectableItemBackground" + android:orientation="horizontal"> + + android:layout_height="48dp" + android:orientation="horizontal"> + tools:ignore="ContentDescription" /> diff --git a/Clover/app/src/main/res/layout/cell_link.xml b/Clover/app/src/main/res/layout/cell_link.xml index 5aede947..4711eeb4 100644 --- a/Clover/app/src/main/res/layout/cell_link.xml +++ b/Clover/app/src/main/res/layout/cell_link.xml @@ -1,18 +1,36 @@ - + + android:background="?attr/selectableItemBackground" + android:orientation="horizontal"> + tools:ignore="ContentDescription" /> + + android:background="?android:attr/selectableItemBackground" + android:orientation="horizontal"> + android:paddingTop="4dp" /> diff --git a/Clover/app/src/main/res/layout/cell_post.xml b/Clover/app/src/main/res/layout/cell_post.xml index 2752ebf3..31105d38 100644 --- a/Clover/app/src/main/res/layout/cell_post.xml +++ b/Clover/app/src/main/res/layout/cell_post.xml @@ -1,5 +1,22 @@ - + @@ -75,6 +92,7 @@ android:paddingLeft="15dp" android:paddingRight="5dp" android:paddingTop="5dp" - android:src="?post_options_drawable" /> + android:src="?post_options_drawable" + tools:ignore="ContentDescription" /> diff --git a/Clover/app/src/main/res/layout/cell_thread_status.xml b/Clover/app/src/main/res/layout/cell_thread_status.xml index 99cd5a3f..02ac1d40 100644 --- a/Clover/app/src/main/res/layout/cell_thread_status.xml +++ b/Clover/app/src/main/res/layout/cell_thread_status.xml @@ -1,4 +1,20 @@ - + + android:layout_height="match_parent" + android:gravity="center" + android:textColor="#ff757575" /> diff --git a/Clover/app/src/main/res/layout/controller_board_edit.xml b/Clover/app/src/main/res/layout/controller_board_edit.xml index 9ea8948e..51e68433 100644 --- a/Clover/app/src/main/res/layout/controller_board_edit.xml +++ b/Clover/app/src/main/res/layout/controller_board_edit.xml @@ -1,17 +1,33 @@ - + + android:background="#ffffffff" + android:orientation="vertical"> + android:scrollbars="vertical" /> diff --git a/Clover/app/src/main/res/layout/controller_image_viewer.xml b/Clover/app/src/main/res/layout/controller_image_viewer.xml index 9d0daabc..469b02e7 100644 --- a/Clover/app/src/main/res/layout/controller_image_viewer.xml +++ b/Clover/app/src/main/res/layout/controller_image_viewer.xml @@ -1,4 +1,20 @@ - + @@ -10,14 +26,14 @@ + android:layout_height="match_parent" + android:visibility="invisible" /> + android:layout_height="3dp" + android:visibility="gone" /> diff --git a/Clover/app/src/main/res/layout/controller_navigation_drawer.xml b/Clover/app/src/main/res/layout/controller_navigation_drawer.xml index b54672d6..fc9ce774 100644 --- a/Clover/app/src/main/res/layout/controller_navigation_drawer.xml +++ b/Clover/app/src/main/res/layout/controller_navigation_drawer.xml @@ -16,6 +16,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . --> @@ -32,7 +33,8 @@ along with this program. If not, see . android:layout_width="match_parent" android:layout_height="56dp" android:background="@color/primary" - android:elevation="4dp" /> + android:elevation="4dp" + tools:ignore="UnusedAttribute" /> . + android:scrollbars="vertical" /> diff --git a/Clover/app/src/main/res/layout/controller_navigation_image_viewer.xml b/Clover/app/src/main/res/layout/controller_navigation_image_viewer.xml index fc8ded08..8db44f0b 100644 --- a/Clover/app/src/main/res/layout/controller_navigation_image_viewer.xml +++ b/Clover/app/src/main/res/layout/controller_navigation_image_viewer.xml @@ -16,6 +16,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . --> . android:layout_width="match_parent" android:layout_height="56dp" android:background="#e9000000" - android:elevation="4dp" /> + android:elevation="4dp" + tools:ignore="UnusedAttribute" /> + + android:layout_height="match_parent" + android:orientation="vertical"> + android:paddingTop="24dp" + android:text="@string/video_playback_warning" + android:textSize="16sp" /> + android:layout_marginTop="16dp" + android:text="@string/video_playback_ignore" /> diff --git a/Clover/app/src/main/res/layout/watch_description.xml b/Clover/app/src/main/res/layout/dialog_web.xml similarity index 84% rename from Clover/app/src/main/res/layout/watch_description.xml rename to Clover/app/src/main/res/layout/dialog_web.xml index bacd7685..fda6df1d 100644 --- a/Clover/app/src/main/res/layout/watch_description.xml +++ b/Clover/app/src/main/res/layout/dialog_web.xml @@ -18,15 +18,13 @@ along with this program. If not, see . + android:paddingTop="16dp"> - + android:scrollbars="vertical" /> diff --git a/Clover/app/src/main/res/layout/folder_pick.xml b/Clover/app/src/main/res/layout/fragment_folder_pick.xml similarity index 93% rename from Clover/app/src/main/res/layout/folder_pick.xml rename to Clover/app/src/main/res/layout/fragment_folder_pick.xml index c201752b..43ce76b2 100644 --- a/Clover/app/src/main/res/layout/folder_pick.xml +++ b/Clover/app/src/main/res/layout/fragment_folder_pick.xml @@ -44,7 +44,7 @@ along with this program. If not, see . android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" - android:drawableLeft="@drawable/ic_action_cancel" + android:drawableLeft="@drawable/ic_arrow_back_black_24dp" android:drawablePadding="8dp" android:gravity="center_vertical" android:paddingRight="20dp" @@ -64,15 +64,15 @@ along with this program. If not, see . android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" - android:drawableLeft="@drawable/ic_action_done" + android:drawableLeft="@drawable/ic_done_black_24dp" android:drawablePadding="8dp" android:gravity="center_vertical" android:paddingRight="20dp" - android:text="@string/folder_pick_ok" /> + android:text="@string/setting_folder_pick_ok" /> - - - - - - - - - - - - - - - - diff --git a/Clover/app/src/main/res/layout/image_view.xml b/Clover/app/src/main/res/layout/image_view.xml deleted file mode 100644 index 32568011..00000000 --- a/Clover/app/src/main/res/layout/image_view.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - diff --git a/Clover/app/src/main/res/layout/layout_reply.xml b/Clover/app/src/main/res/layout/layout_reply.xml deleted file mode 100644 index 1ef45416..00000000 --- a/Clover/app/src/main/res/layout/layout_reply.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - diff --git a/Clover/app/src/main/res/layout/layout_reply_input.xml b/Clover/app/src/main/res/layout/layout_reply_input.xml index 440af286..418dab17 100644 --- a/Clover/app/src/main/res/layout/layout_reply_input.xml +++ b/Clover/app/src/main/res/layout/layout_reply_input.xml @@ -1,4 +1,20 @@ - + + + android:layout_marginBottom="16dp" + android:textSize="24sp" />