From 9db537d339faa3ad44dfdcadb23f4c14bd8aceb4 Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Thu, 5 Oct 2017 15:58:59 +0900 Subject: kotlin work part. 1 --- .../net/lacolaco/smileessence/Application.java | 113 ------ .../java/net/lacolaco/smileessence/Application.kt | 112 ++++++ .../net/lacolaco/smileessence/IntentRouter.java | 143 ------- .../java/net/lacolaco/smileessence/IntentRouter.kt | 142 +++++++ .../main/java/net/lacolaco/smileessence/World.java | 252 ------------ .../main/java/net/lacolaco/smileessence/World.kt | 230 +++++++++++ .../activity/EditExtractionActivity.java | 170 --------- .../activity/EditExtractionActivity.kt | 153 ++++++++ .../smileessence/activity/LicenseActivity.java | 83 ---- .../smileessence/activity/LicenseActivity.kt | 81 ++++ .../smileessence/activity/MainActivity.java | 347 ----------------- .../lacolaco/smileessence/activity/MainActivity.kt | 311 +++++++++++++++ .../activity/ManageAccountsActivity.java | 257 ------------- .../activity/ManageAccountsActivity.kt | 241 ++++++++++++ .../smileessence/activity/OAuthActivity.java | 102 ----- .../smileessence/activity/OAuthActivity.kt | 95 +++++ .../smileessence/activity/SettingActivity.java | 51 --- .../smileessence/activity/SettingActivity.kt | 49 +++ .../net/lacolaco/smileessence/command/Command.java | 44 --- .../net/lacolaco/smileessence/command/Command.kt | 35 ++ .../smileessence/command/CommandAddHashtag.java | 56 --- .../smileessence/command/CommandAddHashtag.kt | 48 +++ .../smileessence/command/CommandOpenURL.java | 57 --- .../smileessence/command/CommandOpenURL.kt | 46 +++ .../command/CommandOpenUserDetail.java | 68 ---- .../smileessence/command/CommandOpenUserDetail.kt | 58 +++ .../lacolaco/smileessence/compat/Twitter4J.java | 11 + .../net/lacolaco/smileessence/data/Account.java | 149 -------- .../java/net/lacolaco/smileessence/data/Account.kt | 134 +++++++ .../lacolaco/smileessence/data/ExtractionWord.java | 81 ---- .../lacolaco/smileessence/data/ExtractionWord.kt | 54 +++ .../net/lacolaco/smileessence/data/ImageCache.java | 65 ---- .../net/lacolaco/smileessence/data/ImageCache.kt | 64 ++++ .../net/lacolaco/smileessence/data/OrmaHolder.java | 19 - .../net/lacolaco/smileessence/data/OrmaHolder.kt | 16 + .../net/lacolaco/smileessence/data/PostState.java | 184 --------- .../net/lacolaco/smileessence/data/PostState.kt | 167 ++++++++ .../smileessence/entity/DirectMessage.java | 71 ---- .../lacolaco/smileessence/entity/DirectMessage.kt | 44 +++ .../smileessence/entity/EntitySupport.java | 121 ------ .../lacolaco/smileessence/entity/EntitySupport.kt | 106 ++++++ .../net/lacolaco/smileessence/entity/Event.java | 62 --- .../java/net/lacolaco/smileessence/entity/Event.kt | 20 + .../net/lacolaco/smileessence/entity/IdObject.java | 5 - .../net/lacolaco/smileessence/entity/IdObject.kt | 5 + .../net/lacolaco/smileessence/entity/RBinding.java | 12 - .../net/lacolaco/smileessence/entity/RBinding.kt | 12 + .../lacolaco/smileessence/entity/SavedSearch.java | 24 -- .../lacolaco/smileessence/entity/SavedSearch.kt | 10 + .../net/lacolaco/smileessence/entity/Tweet.java | 281 -------------- .../java/net/lacolaco/smileessence/entity/Tweet.kt | 197 ++++++++++ .../net/lacolaco/smileessence/entity/User.java | 183 --------- .../java/net/lacolaco/smileessence/entity/User.kt | 136 +++++++ .../net/lacolaco/smileessence/logging/Logger.java | 66 ---- .../net/lacolaco/smileessence/logging/Logger.kt | 67 ++++ .../preference/InternalPreferenceHelper.java | 50 --- .../preference/InternalPreferenceHelper.kt | 44 +++ .../preference/SharedPreferenceHelper.java | 125 ------ .../preference/SharedPreferenceHelper.kt | 127 +++++++ .../preference/UserPreferenceHelper.java | 58 --- .../preference/UserPreferenceHelper.kt | 50 +++ .../smileessence/twitter/OAuthSession.java | 66 ---- .../lacolaco/smileessence/twitter/OAuthSession.kt | 72 ++++ .../smileessence/twitter/UserStreamListener.java | 235 ------------ .../smileessence/twitter/UserStreamListener.kt | 182 +++++++++ .../smileessence/twitter/task/Accounts.java | 90 ----- .../lacolaco/smileessence/twitter/task/Accounts.kt | 65 ++++ .../smileessence/twitter/task/Messages.java | 68 ---- .../lacolaco/smileessence/twitter/task/Messages.kt | 40 ++ .../smileessence/twitter/task/Searches.java | 80 ---- .../lacolaco/smileessence/twitter/task/Searches.kt | 51 +++ .../smileessence/twitter/task/TimelineTask.java | 57 --- .../smileessence/twitter/task/TimelineTask.kt | 51 +++ .../smileessence/twitter/task/Timelines.java | 94 ----- .../smileessence/twitter/task/Timelines.kt | 72 ++++ .../smileessence/twitter/task/TweetReactions.java | 74 ---- .../smileessence/twitter/task/TweetReactions.kt | 56 +++ .../lacolaco/smileessence/twitter/task/Tweets.java | 153 -------- .../lacolaco/smileessence/twitter/task/Tweets.kt | 125 ++++++ .../lacolaco/smileessence/twitter/task/Users.java | 143 ------- .../lacolaco/smileessence/twitter/task/Users.kt | 92 +++++ .../lacolaco/smileessence/util/BackgroundTask.java | 111 ------ .../lacolaco/smileessence/util/BackgroundTask.kt | 113 ++++++ .../smileessence/util/BitmapOptimizer.java | 119 ------ .../lacolaco/smileessence/util/BitmapOptimizer.kt | 122 ++++++ .../smileessence/util/BitmapThumbnailTask.java | 72 ---- .../smileessence/util/BitmapThumbnailTask.kt | 64 ++++ .../lacolaco/smileessence/util/BitmapURLTask.java | 80 ---- .../lacolaco/smileessence/util/BitmapURLTask.kt | 68 ++++ .../net/lacolaco/smileessence/util/Consumer.java | 5 - .../net/lacolaco/smileessence/util/Function.java | 5 - .../lacolaco/smileessence/util/IntentUtils.java | 93 ----- .../net/lacolaco/smileessence/util/IntentUtils.kt | 91 +++++ .../net/lacolaco/smileessence/util/ListUtils.java | 24 -- .../net/lacolaco/smileessence/util/Predicate.java | 5 - .../lacolaco/smileessence/util/StringUtils.java | 61 --- .../net/lacolaco/smileessence/util/StringUtils.kt | 61 +++ .../smileessence/util/SystemServiceHelper.java | 53 --- .../smileessence/util/SystemServiceHelper.kt | 53 +++ .../net/lacolaco/smileessence/util/UIHandler.java | 34 -- .../net/lacolaco/smileessence/util/UIHandler.kt | 30 ++ .../lacolaco/smileessence/util/UIObservable.java | 38 -- .../net/lacolaco/smileessence/util/UIObservable.kt | 38 ++ .../net/lacolaco/smileessence/util/UIObserver.java | 9 - .../smileessence/util/UIObserverBundle.java | 31 -- .../lacolaco/smileessence/util/UIObserverBundle.kt | 26 ++ .../smileessence/view/ColoredRelativeLayout.java | 61 --- .../smileessence/view/ColoredRelativeLayout.kt | 50 +++ .../lacolaco/smileessence/view/DialogHelper.java | 59 --- .../net/lacolaco/smileessence/view/DialogHelper.kt | 59 +++ .../smileessence/view/ExpandedListView.java | 29 -- .../lacolaco/smileessence/view/ExpandedListView.kt | 23 ++ .../net/lacolaco/smileessence/view/Partials.java | 229 ----------- .../net/lacolaco/smileessence/view/Partials.kt | 220 +++++++++++ .../smileessence/view/SettingFragment.java | 147 ------- .../lacolaco/smileessence/view/SettingFragment.kt | 140 +++++++ .../smileessence/view/ThreeStateButton.java | 56 --- .../lacolaco/smileessence/view/ThreeStateButton.kt | 41 ++ .../smileessence/view/ToggleableImageButton.java | 37 -- .../smileessence/view/ToggleableImageButton.kt | 25 ++ .../view/adapter/CustomListAdapter.java | 50 --- .../smileessence/view/adapter/CustomListAdapter.kt | 45 +++ .../view/adapter/EventListAdapter.java | 116 ------ .../smileessence/view/adapter/EventListAdapter.kt | 102 +++++ .../view/adapter/MessageListAdapter.java | 53 --- .../view/adapter/MessageListAdapter.kt | 43 +++ .../view/adapter/OrderedCustomListAdapter.java | 41 -- .../view/adapter/OrderedCustomListAdapter.kt | 35 ++ .../smileessence/view/adapter/PageListAdapter.java | 140 ------- .../smileessence/view/adapter/PageListAdapter.kt | 110 ++++++ .../smileessence/view/adapter/TimelineAdapter.java | 39 -- .../smileessence/view/adapter/TimelineAdapter.kt | 29 ++ .../view/dialog/ConfirmDialogFragment.java | 119 ------ .../view/dialog/ConfirmDialogFragment.kt | 119 ++++++ .../smileessence/view/dialog/DisposeDialog.java | 43 --- .../smileessence/view/dialog/DisposeDialog.kt | 37 ++ .../view/dialog/EditTextDialogFragment.java | 80 ---- .../view/dialog/EditTextDialogFragment.kt | 81 ++++ .../view/dialog/MessageDetailDialogFragment.java | 250 ------------ .../view/dialog/MessageDetailDialogFragment.kt | 246 ++++++++++++ .../view/dialog/SendMessageDialogFragment.java | 131 ------- .../view/dialog/SendMessageDialogFragment.kt | 127 +++++++ .../view/dialog/StackableDialogFragment.java | 28 -- .../view/dialog/StackableDialogFragment.kt | 25 ++ .../view/dialog/StatusDetailDialogFragment.java | 348 ----------------- .../view/dialog/StatusDetailDialogFragment.kt | 339 +++++++++++++++++ .../view/dialog/TalkChainDialogFragment.java | 89 ----- .../view/dialog/TalkChainDialogFragment.kt | 81 ++++ .../view/dialog/UserDetailDialogFragment.java | 423 --------------------- .../view/dialog/UserDetailDialogFragment.kt | 390 +++++++++++++++++++ .../view/listener/ListItemClickListener.java | 63 --- .../view/listener/ListItemClickListener.kt | 56 +++ .../smileessence/view/page/CustomListFragment.java | 117 ------ .../smileessence/view/page/CustomListFragment.kt | 107 ++++++ .../smileessence/view/page/HistoryFragment.java | 46 --- .../smileessence/view/page/HistoryFragment.kt | 41 ++ .../smileessence/view/page/HomeFragment.java | 104 ----- .../smileessence/view/page/HomeFragment.kt | 97 +++++ .../smileessence/view/page/MentionsFragment.java | 112 ------ .../smileessence/view/page/MentionsFragment.kt | 102 +++++ .../smileessence/view/page/MessagesFragment.java | 97 ----- .../smileessence/view/page/MessagesFragment.kt | 90 +++++ .../smileessence/view/page/PageFragment.java | 32 -- .../smileessence/view/page/PageFragment.kt | 25 ++ .../smileessence/view/page/PostFragment.java | 334 ---------------- .../smileessence/view/page/PostFragment.kt | 304 +++++++++++++++ .../smileessence/view/page/SearchFragment.java | 321 ---------------- .../smileessence/view/page/SearchFragment.kt | 299 +++++++++++++++ .../smileessence/view/page/UserListFragment.java | 192 ---------- .../smileessence/view/page/UserListFragment.kt | 179 +++++++++ .../view/preference/IntegerEditTextPreference.java | 36 -- .../view/preference/IntegerEditTextPreference.kt | 26 ++ .../view/preference/IntegerListPreference.java | 37 -- .../view/preference/IntegerListPreference.kt | 27 ++ 174 files changed, 8057 insertions(+), 9158 deletions(-) delete mode 100644 app/src/main/java/net/lacolaco/smileessence/Application.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/Application.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/IntentRouter.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/IntentRouter.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/World.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/World.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/activity/EditExtractionActivity.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/activity/EditExtractionActivity.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/activity/LicenseActivity.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/activity/LicenseActivity.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/activity/MainActivity.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/activity/MainActivity.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/activity/ManageAccountsActivity.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/activity/ManageAccountsActivity.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/activity/OAuthActivity.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/activity/OAuthActivity.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/activity/SettingActivity.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/activity/SettingActivity.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/command/Command.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/command/Command.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/command/CommandAddHashtag.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/command/CommandAddHashtag.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/command/CommandOpenURL.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/command/CommandOpenURL.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/command/CommandOpenUserDetail.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/command/CommandOpenUserDetail.kt create mode 100644 app/src/main/java/net/lacolaco/smileessence/compat/Twitter4J.java delete mode 100644 app/src/main/java/net/lacolaco/smileessence/data/Account.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/data/Account.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/data/ExtractionWord.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/data/ExtractionWord.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/data/ImageCache.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/data/ImageCache.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/data/OrmaHolder.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/data/OrmaHolder.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/data/PostState.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/data/PostState.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/entity/DirectMessage.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/entity/DirectMessage.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/entity/EntitySupport.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/entity/EntitySupport.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/entity/Event.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/entity/Event.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/entity/IdObject.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/entity/IdObject.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/entity/RBinding.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/entity/RBinding.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/entity/SavedSearch.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/entity/SavedSearch.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/entity/Tweet.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/entity/Tweet.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/entity/User.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/entity/User.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/logging/Logger.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/logging/Logger.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/preference/InternalPreferenceHelper.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/preference/InternalPreferenceHelper.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/preference/SharedPreferenceHelper.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/preference/SharedPreferenceHelper.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/preference/UserPreferenceHelper.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/preference/UserPreferenceHelper.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/twitter/OAuthSession.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/twitter/OAuthSession.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/twitter/UserStreamListener.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/twitter/UserStreamListener.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/twitter/task/Accounts.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/twitter/task/Accounts.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/twitter/task/Messages.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/twitter/task/Messages.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/twitter/task/Searches.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/twitter/task/Searches.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/twitter/task/TimelineTask.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/twitter/task/TimelineTask.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/twitter/task/Timelines.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/twitter/task/Timelines.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/twitter/task/TweetReactions.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/twitter/task/TweetReactions.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/twitter/task/Tweets.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/twitter/task/Tweets.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/twitter/task/Users.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/twitter/task/Users.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/util/BackgroundTask.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/util/BackgroundTask.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/util/BitmapOptimizer.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/util/BitmapOptimizer.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/util/BitmapThumbnailTask.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/util/BitmapThumbnailTask.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/util/BitmapURLTask.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/util/BitmapURLTask.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/util/Consumer.java delete mode 100644 app/src/main/java/net/lacolaco/smileessence/util/Function.java delete mode 100644 app/src/main/java/net/lacolaco/smileessence/util/IntentUtils.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/util/IntentUtils.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/util/ListUtils.java delete mode 100644 app/src/main/java/net/lacolaco/smileessence/util/Predicate.java delete mode 100644 app/src/main/java/net/lacolaco/smileessence/util/StringUtils.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/util/StringUtils.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/util/SystemServiceHelper.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/util/SystemServiceHelper.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/util/UIHandler.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/util/UIHandler.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/util/UIObservable.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/util/UIObservable.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/util/UIObserver.java delete mode 100644 app/src/main/java/net/lacolaco/smileessence/util/UIObserverBundle.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/util/UIObserverBundle.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/ColoredRelativeLayout.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/ColoredRelativeLayout.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/DialogHelper.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/DialogHelper.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/ExpandedListView.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/ExpandedListView.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/Partials.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/Partials.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/SettingFragment.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/SettingFragment.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/ThreeStateButton.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/ThreeStateButton.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/ToggleableImageButton.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/ToggleableImageButton.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/adapter/CustomListAdapter.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/adapter/CustomListAdapter.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/adapter/EventListAdapter.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/adapter/EventListAdapter.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/adapter/MessageListAdapter.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/adapter/MessageListAdapter.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/adapter/OrderedCustomListAdapter.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/adapter/OrderedCustomListAdapter.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/adapter/PageListAdapter.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/adapter/PageListAdapter.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/adapter/TimelineAdapter.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/adapter/TimelineAdapter.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/dialog/ConfirmDialogFragment.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/dialog/ConfirmDialogFragment.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/dialog/DisposeDialog.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/dialog/DisposeDialog.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/dialog/EditTextDialogFragment.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/dialog/EditTextDialogFragment.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/dialog/MessageDetailDialogFragment.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/dialog/MessageDetailDialogFragment.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/dialog/SendMessageDialogFragment.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/dialog/SendMessageDialogFragment.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/dialog/StackableDialogFragment.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/dialog/StackableDialogFragment.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/dialog/StatusDetailDialogFragment.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/dialog/StatusDetailDialogFragment.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/dialog/TalkChainDialogFragment.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/dialog/TalkChainDialogFragment.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/dialog/UserDetailDialogFragment.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/dialog/UserDetailDialogFragment.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/listener/ListItemClickListener.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/listener/ListItemClickListener.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/page/CustomListFragment.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/page/CustomListFragment.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/page/HistoryFragment.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/page/HistoryFragment.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/page/HomeFragment.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/page/HomeFragment.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/page/MentionsFragment.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/page/MentionsFragment.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/page/MessagesFragment.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/page/MessagesFragment.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/page/PageFragment.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/page/PageFragment.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/page/PostFragment.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/page/PostFragment.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/page/SearchFragment.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/page/SearchFragment.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/page/UserListFragment.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/page/UserListFragment.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/preference/IntegerEditTextPreference.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/preference/IntegerEditTextPreference.kt delete mode 100644 app/src/main/java/net/lacolaco/smileessence/view/preference/IntegerListPreference.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/view/preference/IntegerListPreference.kt (limited to 'app/src') diff --git a/app/src/main/java/net/lacolaco/smileessence/Application.java b/app/src/main/java/net/lacolaco/smileessence/Application.java deleted file mode 100644 index adefcae1..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/Application.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence; - -import android.support.annotation.StringRes; -import android.widget.Toast; -import com.crashlytics.android.Crashlytics; -import com.crashlytics.android.core.CrashlyticsCore; -import com.squareup.leakcanary.LeakCanary; -import io.fabric.sdk.android.Fabric; -import net.lacolaco.smileessence.data.Account; -import net.lacolaco.smileessence.data.OrmaHolder; -import net.lacolaco.smileessence.logging.Logger; - -import java.lang.ref.WeakReference; -import java.util.HashMap; -import java.util.Map; - -/** - * プロセスと同期しているオブジェクト - * 現在のテーマのリソース ID と現在のアカウント(およびアカウント変更イベントリスナー)を保持します - * MainActivity の onCreate で resetState を呼び、保持しているデータを破棄すること - */ -public class Application extends android.app.Application { - private static Application instance; - private static WeakReference lastWorld; - private static Map> worlds = new HashMap<>(); // XXX - - @Deprecated - public static Application getInstance() { - Application obj = instance; - if (obj == null) { - throw new IllegalStateException("[BUG] Application is not initialized?"); - } else { - return obj; - } - } - - // --------------------- get instance --------------------- - - public static void toast(@StringRes int id) { - Toast.makeText(instance, id, Toast.LENGTH_LONG).show(); - } - - public static void toast(String text) { - Toast.makeText(instance, text, Toast.LENGTH_LONG).show(); - } - - @Override - public void onCreate() { - super.onCreate(); - if (LeakCanary.isInAnalyzerProcess(this)) { - return; - } - LeakCanary.install(this); - - Fabric.with(this, new Crashlytics.Builder().core(new CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build()).build()); - OrmaHolder.initialize(this); - - // Load eagarly - Account.load(); - instance = this; // プロセスの寿命の間 1 度しか呼ばれないので安全 - Logger.debug("onCreate"); - } - - public static World getCurrentWorld() { - World w0 = lastWorld != null ? lastWorld.get() : null; - if (w0 != null) - return w0; - for (WeakReference ww : worlds.values()) { - World w = ww.get(); - if (w != null) - return w; - } - return null; - } - - public static World getWorld(long id) { - WeakReference ww = worlds.get(id); - if (ww != null) { - World w = ww.get(); - if (w != null) { - lastWorld = ww; - return w; - } - } - World w = new World(Account.get(id)); - worlds.put(id, lastWorld = new WeakReference<>(w)); - return w; - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/Application.kt b/app/src/main/java/net/lacolaco/smileessence/Application.kt new file mode 100644 index 00000000..7950d62a --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/Application.kt @@ -0,0 +1,112 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence + +import android.support.annotation.StringRes +import android.widget.Toast +import com.crashlytics.android.Crashlytics +import com.crashlytics.android.core.CrashlyticsCore +import com.squareup.leakcanary.LeakCanary +import io.fabric.sdk.android.Fabric +import net.lacolaco.smileessence.data.Account +import net.lacolaco.smileessence.data.OrmaHolder +import net.lacolaco.smileessence.logging.Logger + +import java.lang.ref.WeakReference +import java.util.HashMap + +/** + * プロセスと同期しているオブジェクト + * 現在のテーマのリソース ID と現在のアカウント(およびアカウント変更イベントリスナー)を保持します + * MainActivity の onCreate で resetState を呼び、保持しているデータを破棄すること + */ +class Application : android.app.Application() { + + override fun onCreate() { + super.onCreate() + if (LeakCanary.isInAnalyzerProcess(this)) { + return + } + LeakCanary.install(this) + + Fabric.with(this, Crashlytics.Builder().core(CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build()).build()) + OrmaHolder.initialize(this) + + // Load eagarly + Account.load() + instancex = this // プロセスの寿命の間 1 度しか呼ばれないので安全 + Logger.debug("onCreate") + } + + companion object { + private var instancex: Application? = null + private var lastWorld: WeakReference? = null + private val worlds = HashMap>() // XXX + + @Deprecated("") + fun getInstance(): Application { + val obj = instancex + return obj ?: throw IllegalStateException("[BUG] Application is not initialized?") + } + + // --------------------- get instance --------------------- + + fun toast(@StringRes id: Int) { + Toast.makeText(instancex, id, Toast.LENGTH_LONG).show() + } + + fun toast(text: String) { + Toast.makeText(instancex, text, Toast.LENGTH_LONG).show() + } + + val currentWorld: World? + get() { + val w0 = if (lastWorld != null) lastWorld!!.get() else null + if (w0 != null) + return w0 + for (ww in worlds.values) { + val w = ww.get() + if (w != null) + return w + } + return null + } + + fun getWorld(id: Long): World { + val ww0 = worlds[id] + if (ww0 != null) { + val w0 = ww0.get() + if (w0 != null) { + lastWorld = ww0 + return w0 + } + } + val w = World(Account.get(id)) + val ww = WeakReference(w) + worlds.put(id, ww) + return w + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/IntentRouter.java b/app/src/main/java/net/lacolaco/smileessence/IntentRouter.java deleted file mode 100644 index 84e41ff6..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/IntentRouter.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence; - -import android.app.Activity; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.text.TextUtils; -import android.widget.Toast; -import net.lacolaco.smileessence.activity.MainActivity; -import net.lacolaco.smileessence.command.CommandOpenUserDetail; -import net.lacolaco.smileessence.entity.Tweet; -import net.lacolaco.smileessence.logging.Logger; -import net.lacolaco.smileessence.util.UIHandler; -import net.lacolaco.smileessence.view.DialogHelper; -import net.lacolaco.smileessence.view.dialog.StatusDetailDialogFragment; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class IntentRouter { - - // ------------------------------ FIELDS ------------------------------ - - private static final String TWITTER_HOST = "twitter.com"; - private static final Pattern TWITTER_STATUS_PATTERN = Pattern.compile("\\A(?:/#!)?/(?:\\w{1,15})/status(?:es)?/(\\d+)\\z", Pattern.CASE_INSENSITIVE); - private static final Pattern TWITTER_USER_PATTERN = Pattern.compile("\\A(?:/#!)?/(\\w{1,15})/?\\z", Pattern.CASE_INSENSITIVE); - private static final Pattern TWITTER_POST_PATTERN = Pattern.compile("\\A/(intent/tweet|share)\\z", Pattern.CASE_INSENSITIVE); - - // -------------------------- STATIC METHODS -------------------------- - - public static void onNewIntent(MainActivity activity, Intent intent) { - Logger.debug("onNewIntent"); - Uri uri = intent.getData(); - if (uri != null) { - onUriIntent(activity, uri); - } else if (intent.getAction() != null) { - switch (intent.getAction()) { - case Intent.ACTION_SEND: { - if ("text/plain".equals(intent.getType())) { - Bundle extra = intent.getExtras(); - if (extra != null) { - String text = getText(extra); - openPostPage(activity, text); - } - } else if (intent.getType().startsWith("image/")) { - Uri imageUri = intent.getParcelableExtra(Intent.EXTRA_STREAM); - openPostPageWithImage(activity, imageUri); - } - break; - } - } - } - } - - private static void onUriIntent(MainActivity activity, Uri uri) { - Logger.debug(uri.toString()); - - if (uri.getHost().equals(TWITTER_HOST)) { - Matcher postMatcher = TWITTER_POST_PATTERN.matcher(uri.getPath()); // /share and /intent/tweet: don't accept status parameter - if (postMatcher.find()) { - openPostPage(activity, extractText(uri)); - return; - } - Matcher statusMatcher = TWITTER_STATUS_PATTERN.matcher(uri.getPath()); - if (statusMatcher.find()) { - showStatusDialog(activity, Long.parseLong(statusMatcher.group(1))); - return; - } - Matcher userMatcher = TWITTER_USER_PATTERN.matcher(uri.getPath()); - if (userMatcher.find()) { - showUserDialog(activity, userMatcher.group(1)); - } - } - } - - private static String getText(Bundle extra) { - StringBuilder builder = new StringBuilder(); - if (!TextUtils.isEmpty(extra.getCharSequence(Intent.EXTRA_SUBJECT))) { - builder.append(extra.getCharSequence(Intent.EXTRA_SUBJECT)).append(" "); - } - builder.append(extra.getCharSequence(Intent.EXTRA_TEXT)); - return builder.toString(); - } - - private static String extractText(Uri uri) { - String result = ""; - String text = uri.getQueryParameter("text"); - String url = uri.getQueryParameter("url"); - String via = uri.getQueryParameter("via"); - String hashtags = uri.getQueryParameter("hashtags"); - - if (!TextUtils.isEmpty(text)) result += text; - if (!TextUtils.isEmpty(url)) result += " " + url; - if (!TextUtils.isEmpty(hashtags)) result += " " + hashtags.trim().replaceAll(",", " #"); - if (!TextUtils.isEmpty(via)) result += " via @" + via; - - return result; - } - - private static void showStatusDialog(Activity activity, long id) { - Tweet.fetchTask(id, Application.getCurrentWorld().getAccount()) - .onDoneUI(tweet -> DialogHelper.showDialog(activity, StatusDetailDialogFragment.newInstance(tweet))) - .onFail(x -> Application.toast(R.string.error_intent_status_cannot_load)) - .execute(); - } - - private static void showUserDialog(MainActivity activity, String screenName) { - CommandOpenUserDetail openUserDetail = new CommandOpenUserDetail(activity, screenName); - openUserDetail.execute(); - } - - private static void openPostPage(final MainActivity activity, final String str) { - new UIHandler().post(() -> activity.getWorld().getPostState().beginTransaction().setText(str).commitWithOpen(activity)); - } - - private static void openPostPageWithImage(final MainActivity activity, final Uri imageUri) { - new UIHandler().post(() -> activity.openPostPageWithImage(imageUri)); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/IntentRouter.kt b/app/src/main/java/net/lacolaco/smileessence/IntentRouter.kt new file mode 100644 index 00000000..e5f9d0ce --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/IntentRouter.kt @@ -0,0 +1,142 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence + +import android.app.Activity +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import android.text.TextUtils +import android.widget.Toast +import net.lacolaco.smileessence.activity.MainActivity +import net.lacolaco.smileessence.command.CommandOpenUserDetail +import net.lacolaco.smileessence.entity.Tweet +import net.lacolaco.smileessence.logging.Logger +import net.lacolaco.smileessence.util.UIHandler +import net.lacolaco.smileessence.view.DialogHelper +import net.lacolaco.smileessence.view.dialog.StatusDetailDialogFragment + +import java.util.regex.Matcher +import java.util.regex.Pattern + +object IntentRouter { + + // ------------------------------ FIELDS ------------------------------ + + private val TWITTER_HOST = "twitter.com" + private val TWITTER_STATUS_PATTERN = Pattern.compile("\\A(?:/#!)?/(?:\\w{1,15})/status(?:es)?/(\\d+)\\z", Pattern.CASE_INSENSITIVE) + private val TWITTER_USER_PATTERN = Pattern.compile("\\A(?:/#!)?/(\\w{1,15})/?\\z", Pattern.CASE_INSENSITIVE) + private val TWITTER_POST_PATTERN = Pattern.compile("\\A/(intent/tweet|share)\\z", Pattern.CASE_INSENSITIVE) + + // -------------------------- STATIC METHODS -------------------------- + + fun onNewIntent(activity: MainActivity, intent: Intent) { + Logger.debug("onNewIntent") + val uri = intent.data + if (uri != null) { + onUriIntent(activity, uri) + } else if (intent.action != null) { + when (intent.action) { + Intent.ACTION_SEND -> { + if ("text/plain" == intent.type) { + val extra = intent.extras + if (extra != null) { + val text = getText(extra) + openPostPage(activity, text) + } + } else if (intent.type.startsWith("image/")) { + val imageUri = intent.getParcelableExtra(Intent.EXTRA_STREAM) + openPostPageWithImage(activity, imageUri) + } + } + } + } + } + + private fun onUriIntent(activity: MainActivity, uri: Uri) { + Logger.debug(uri.toString()) + + if (uri.host == TWITTER_HOST) { + val postMatcher = TWITTER_POST_PATTERN.matcher(uri.path) // /share and /intent/tweet: don't accept status parameter + if (postMatcher.find()) { + openPostPage(activity, extractText(uri)) + return + } + val statusMatcher = TWITTER_STATUS_PATTERN.matcher(uri.path) + if (statusMatcher.find()) { + showStatusDialog(activity, java.lang.Long.parseLong(statusMatcher.group(1))) + return + } + val userMatcher = TWITTER_USER_PATTERN.matcher(uri.path) + if (userMatcher.find()) { + showUserDialog(activity, userMatcher.group(1)) + } + } + } + + private fun getText(extra: Bundle): String { + val builder = StringBuilder() + if (!TextUtils.isEmpty(extra.getCharSequence(Intent.EXTRA_SUBJECT))) { + builder.append(extra.getCharSequence(Intent.EXTRA_SUBJECT)).append(" ") + } + builder.append(extra.getCharSequence(Intent.EXTRA_TEXT)) + return builder.toString() + } + + private fun extractText(uri: Uri): String { + var result = "" + val text = uri.getQueryParameter("text") + val url = uri.getQueryParameter("url") + val via = uri.getQueryParameter("via") + val hashtags = uri.getQueryParameter("hashtags") + + if (!TextUtils.isEmpty(text)) result += text + if (!TextUtils.isEmpty(url)) result += " " + url + if (!TextUtils.isEmpty(hashtags)) result += " " + hashtags.trim { it <= ' ' }.replace(",".toRegex(), " #") + if (!TextUtils.isEmpty(via)) result += " via @" + via + + return result + } + + private fun showStatusDialog(activity: Activity, id: Long) { + Tweet.fetchTask(id, Application.currentWorld!!.account) + .onDoneUI { tweet -> DialogHelper.showDialog(activity, StatusDetailDialogFragment.newInstance(tweet)) } + .onFail { x -> Application.toast(R.string.error_intent_status_cannot_load) } + .execute() + } + + private fun showUserDialog(activity: MainActivity, screenName: String) { + val openUserDetail = CommandOpenUserDetail(activity, screenName) + openUserDetail.execute() + } + + private fun openPostPage(activity: MainActivity, str: String) { + UIHandler().post { activity.world.postState.beginTransaction().setText(str).commitWithOpen(activity) } + } + + private fun openPostPageWithImage(activity: MainActivity, imageUri: Uri) { + UIHandler().post { activity.openPostPageWithImage(imageUri) } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/World.java b/app/src/main/java/net/lacolaco/smileessence/World.java deleted file mode 100644 index ae9c68cd..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/World.java +++ /dev/null @@ -1,252 +0,0 @@ -package net.lacolaco.smileessence; - -import android.content.Context; -import android.support.annotation.StringRes; -import de.keyboardsurfer.android.widget.crouton.Configuration; -import de.keyboardsurfer.android.widget.crouton.Crouton; -import de.keyboardsurfer.android.widget.crouton.Style; -import net.lacolaco.smileessence.activity.MainActivity; -import net.lacolaco.smileessence.data.Account; -import net.lacolaco.smileessence.data.PostState; -import net.lacolaco.smileessence.entity.DirectMessage; -import net.lacolaco.smileessence.entity.Event; -import net.lacolaco.smileessence.entity.SavedSearch; -import net.lacolaco.smileessence.entity.Tweet; -import net.lacolaco.smileessence.logging.Logger; -import net.lacolaco.smileessence.preference.UserPreferenceHelper; -import net.lacolaco.smileessence.twitter.UserStreamListener; -import net.lacolaco.smileessence.twitter.task.Accounts; -import net.lacolaco.smileessence.twitter.task.Searches; -import net.lacolaco.smileessence.twitter.task.Users; -import net.lacolaco.smileessence.util.*; -import twitter4j.TwitterStream; - -import java.lang.ref.WeakReference; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; - -/** - * World contains data that are specific to an account. - */ -public class World { - private static final int NOTIFICATION_DURATION = 1000; - private Account account; - private int resId; // XXX: Fetch from Account - // XXX: Move to MainActivity - private PostState postState = new PostState(); - // Timelines - private final List tweets = new ArrayList<>(); - private final WeakHashMap> tweetNotifiers = new WeakHashMap<>(); - // Direct messages - private final Map directMessages = new ConcurrentHashMap<>(); - private final WeakHashMap> directMessageNotifiers = new WeakHashMap<>(); - // Events - private final List events = new ArrayList<>(); - private final WeakHashMap eventNotifiers = new WeakHashMap<>(); - // Streaming APIs - private TwitterStream stream; - private UserStreamListener userStreamListener; - // Lists - private final Set listSubscriptions = Collections.newSetFromMap(new ConcurrentHashMap<>()); - // Mute - private final Set muteUserIds = Collections.newSetFromMap(new ConcurrentHashMap<>()); - // Saved searches - private final Map savedSearches = new HashMap<>(); - // Notification - private WeakReference mainActivity; - private boolean isMainActivityActive; - - public World(Account a) { - account = a; - } - - public Account getAccount() { - return account; - } - - @Deprecated - public void setAccount(Account a) { - account = a; - } - - public PostState getPostState() { - return postState; - } - - // Timelines - - public synchronized void addTimeline(Object key, Consumer notify) { - for (Tweet tweet : tweets) - notify.accept(tweet); - tweetNotifiers.put(key, notify); - } - - public synchronized void addTweet(Tweet tweet) { - tweets.add(tweet); - tweetNotifiers.forEach((o, c) -> c.accept(tweet)); - } - - public synchronized void addTweetAll(Collection ts) { - tweets.addAll(ts); - for (Tweet tweet : ts) { - tweetNotifiers.forEach((o, c) -> c.accept(tweet)); - } - } - - // Direct messages - - public synchronized void addDirectMessageTimeline(Object key, Consumer notify) { - directMessageNotifiers.put(key, notify); - } - - public void addDirectMessage(DirectMessage entity) { - if (directMessages.put(entity.getId(), entity) == null) - directMessageNotifiers.forEach((o, c) -> c.accept(entity)); - } - - // Events - - public synchronized void addEventNotifier(Object key, Runnable notify) { - eventNotifiers.put(key, notify); - } - - public List getEvents() { - return events; - } - - public void addEvent(Event e) { - events.add(e); - eventNotifiers.forEach((o, a) -> a.run()); - } - - // Streaming APIs - - public void setupStreaming() { - if (stream == null) { - stream = account.getTwitterStream(); - userStreamListener = new UserStreamListener(this); - stream.addListener(userStreamListener); - stream.addConnectionLifeCycleListener(userStreamListener); - stream.user(); - } - } - - public boolean isStreaming() { - return stream != null && userStreamListener.isConnected(); - } - - // Lists - - public BackgroundTask, Void> refreshListSubscriptions() { - return new Users.GetManyTask(account) - .onDone(lists -> { - listSubscriptions.clear(); - listSubscriptions.addAll(lists); - }) - // .onFail(x -> { }) // TODO: error message? - .execute(); - } - - public Set getListSubscriptions() { - return listSubscriptions; - } - - public boolean addListSubscription(String fullName) { - return listSubscriptions.add(fullName); - } - - public boolean removeListSubscription(String fullName) { - return listSubscriptions.remove(fullName); - } - - // Mute - - public List refreshUserMuteList() { - List tasks = new ArrayList<>(); - tasks.add(new Accounts.BlockIDsTask(account).onDone(muteUserIds::addAll).execute()); - tasks.add(new Accounts.MutesIDsTask(account).onDone(muteUserIds::addAll).execute()); - return tasks; - } - - public boolean isMutedUserListContains(long id) { - return muteUserIds.contains(id); - } - - // Saved search queries - - public Collection getSavedSearches() { - return savedSearches.values(); - } - - public BackgroundTask, Void> refreshSavedSearches() { - return new Searches.GetAllSavedSearchesTask(account).onDone(ssl -> { - savedSearches.clear(); - for (SavedSearch ss : ssl) - savedSearches.put(ss.getId(), ss); - }).execute(); - } - - // Notifications - - public void setMainActivity(MainActivity activity) { - mainActivity = new WeakReference<>(activity); - } - - public void setMainActivityActive(boolean yes) { - isMainActivityActive = yes; - } - - public void notify(String text) { - doNotify(NotificationType.INFO, text); - } - - public void notify(@StringRes int resId, Object... formatArgs) { - doNotify(NotificationType.INFO, resId, formatArgs); - } - - public void notifyError(String text) { - doNotify(NotificationType.ALERT, text); - } - - public void notifyError(@StringRes int resId, Object... formatArgs) { - doNotify(NotificationType.ALERT, resId, formatArgs); - } - - private void doNotify(NotificationType type, @StringRes int resId, Object... formatArgs) { - Context context = mainActivity.get(); - if (context != null) { - String text = context.getString(resId, formatArgs); - doNotify(type, text); - } else { - Logger.debug("MainActivity is dead"); - } - } - - private void doNotify(NotificationType type, String text) { - MainActivity activity = mainActivity.get(); - if (activity == null || activity.isFinishing()) { - Logger.debug(String.format("notify(log): %s", text)); - } else { - new UIHandler().post(() -> { - if (isMainActivityActive) { - Logger.debug(String.format("notify(crouton): %s", text)); - Configuration.Builder conf = new Configuration.Builder(); - conf.setDuration(NOTIFICATION_DURATION); - Style.Builder bstyle = new Style.Builder(); - bstyle.setConfiguration(conf.build()); - bstyle.setBackgroundColorValue(type == NotificationType.ALERT ? - Style.holoRedLight : Style.holoBlueLight); - Crouton.makeText(activity, text, bstyle.build()).show(); - } else { - Logger.debug(String.format("notify(toast): %s", text)); - Application.toast(text); - } - }); - } - } - - enum NotificationType { - INFO, - ALERT - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/World.kt b/app/src/main/java/net/lacolaco/smileessence/World.kt new file mode 100644 index 00000000..b18522e5 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/World.kt @@ -0,0 +1,230 @@ +package net.lacolaco.smileessence + +import android.support.annotation.StringRes +import de.keyboardsurfer.android.widget.crouton.Configuration +import de.keyboardsurfer.android.widget.crouton.Crouton +import de.keyboardsurfer.android.widget.crouton.Style +import net.lacolaco.smileessence.activity.MainActivity +import net.lacolaco.smileessence.compat.Twitter4J +import net.lacolaco.smileessence.data.Account +import net.lacolaco.smileessence.data.PostState +import net.lacolaco.smileessence.entity.DirectMessage +import net.lacolaco.smileessence.entity.Event +import net.lacolaco.smileessence.entity.SavedSearch +import net.lacolaco.smileessence.entity.Tweet +import net.lacolaco.smileessence.logging.Logger +import net.lacolaco.smileessence.twitter.UserStreamListener +import net.lacolaco.smileessence.twitter.task.Accounts +import net.lacolaco.smileessence.twitter.task.Searches +import net.lacolaco.smileessence.twitter.task.Users +import net.lacolaco.smileessence.util.* +import twitter4j.TwitterStream + +import java.lang.ref.WeakReference +import java.util.* +import java.util.concurrent.ConcurrentHashMap + +/** + * World contains data that are specific to an account. + */ +class World(var account: Account) { + private val resId: Int = 0 // XXX: Fetch from Account + // XXX: Move to MainActivity + val postState = PostState() + // Timelines + private val tweets = ArrayList() + private val tweetNotifiers = WeakHashMap Unit>() + // Direct messages + private val directMessages = ConcurrentHashMap() + private val directMessageNotifiers = WeakHashMap Unit>() + // Events + val events = ArrayList() + private val eventNotifiers = WeakHashMap Unit>() + // Streaming APIs + private var stream: TwitterStream? = null + private var userStreamListener: UserStreamListener? = null + // Lists + val listSubscriptions = Collections.newSetFromMap(ConcurrentHashMap()) + // Mute + private val muteUserIds = Collections.newSetFromMap(ConcurrentHashMap()) + // Saved searches + val savedSearches = HashMap() + // Notification + private var mainActivity: WeakReference? = null + private var isMainActivityActive: Boolean = false + + // Timelines + + @Synchronized + fun addTimeline(key: Any, notify: (Tweet) -> Unit) { + for (tweet in tweets) + notify(tweet) + tweetNotifiers.put(key, notify) + } + + @Synchronized + fun addTweet(tweet: Tweet) { + tweets.add(tweet) + tweetNotifiers.forEach { o, c -> c(tweet) } + } + + @Synchronized + fun addTweetAll(ts: Collection) { + tweets.addAll(ts) + for (tweet in ts) { + tweetNotifiers.forEach { o, c -> c(tweet) } + } + } + + // Direct messages + + @Synchronized + fun addDirectMessageTimeline(key: Any, notify: (DirectMessage) -> Unit) { + directMessageNotifiers.put(key, notify) + } + + fun addDirectMessage(entity: DirectMessage) { + if (directMessages.put(entity.id, entity) == null) + directMessageNotifiers.forEach { o, c -> c(entity) } + } + + // Events + + @Synchronized + fun addEventNotifier(key: Any, notify: () -> Unit) { + eventNotifiers.put(key, notify) + } + + fun addEvent(e: Event) { + events.add(e) + eventNotifiers.forEach { o, a -> a() } + } + + // Streaming APIs + + fun setupStreaming() { + if (stream == null) { + stream = account.twitterStream + userStreamListener = UserStreamListener(this) + Twitter4J.twitterStreamAddListener(stream!!, userStreamListener!!) + stream!!.addConnectionLifeCycleListener(userStreamListener) + stream!!.user() + } + } + + val isStreaming: Boolean + get() = stream != null && userStreamListener!!.isConnected + + // Lists + + fun refreshListSubscriptions(): BackgroundTask, Void> { + return Users.GetManyTask(account) + .onDone { lists -> + listSubscriptions.clear() + listSubscriptions.addAll(lists) + } + // .onFail(x -> { }) // TODO: error message? + .execute() + } + + fun addListSubscription(fullName: String): Boolean { + return listSubscriptions.add(fullName) + } + + fun removeListSubscription(fullName: String): Boolean { + return listSubscriptions.remove(fullName) + } + + // Mute + + fun refreshUserMuteList(): List> { + val tasks = ArrayList>() + tasks.add(Accounts.BlockIDsTask(account).onDone { muteUserIds.addAll(it) }.execute()) + tasks.add(Accounts.MutesIDsTask(account).onDone { muteUserIds.addAll(it) }.execute()) + return tasks + } + + fun isMutedUserListContains(id: Long): Boolean { + return muteUserIds.contains(id) + } + + // Saved search queries + + fun refreshSavedSearches(): BackgroundTask, Void> { + return Searches.GetAllSavedSearchesTask(account).onDone { ssl -> + savedSearches.clear() + for (ss in ssl) + savedSearches.put(ss.id, ss) + }.execute() + } + + // Notifications + + fun setMainActivity(activity: MainActivity) { + mainActivity = WeakReference(activity) + } + + fun setMainActivityActive(yes: Boolean) { + isMainActivityActive = yes + } + + fun notify(text: String) { + doNotify(NotificationType.INFO, text) + } + + fun notify(@StringRes resId: Int, vararg formatArgs: Any) { + doNotify(NotificationType.INFO, resId, *formatArgs) + } + + fun notifyError(text: String) { + doNotify(NotificationType.ALERT, text) + } + + fun notifyError(@StringRes resId: Int, vararg formatArgs: Any) { + doNotify(NotificationType.ALERT, resId, *formatArgs) + } + + private fun doNotify(type: NotificationType, @StringRes resId: Int, vararg formatArgs: Any) { + val context = mainActivity!!.get() + if (context != null) { + val text = context.getString(resId, *formatArgs) + doNotify(type, text) + } else { + Logger.debug("MainActivity is dead") + } + } + + private fun doNotify(type: NotificationType, text: String) { + val activity = mainActivity!!.get() + if (activity == null || activity.isFinishing) { + Logger.debug(String.format("notify(log): %s", text)) + } else { + UIHandler().post { + if (isMainActivityActive) { + Logger.debug(String.format("notify(crouton): %s", text)) + val conf = Configuration.Builder() + conf.setDuration(NOTIFICATION_DURATION) + val bstyle = Style.Builder() + bstyle.setConfiguration(conf.build()) + bstyle.setBackgroundColorValue(if (type == NotificationType.ALERT) + Style.holoRedLight + else + Style.holoBlueLight) + Crouton.makeText(activity, text, bstyle.build()).show() + } else { + Logger.debug(String.format("notify(toast): %s", text)) + Application.toast(text) + } + } + } + } + + internal enum class NotificationType { + INFO, + ALERT + } + + companion object { + private val NOTIFICATION_DURATION = 1000 + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/activity/EditExtractionActivity.java b/app/src/main/java/net/lacolaco/smileessence/activity/EditExtractionActivity.java deleted file mode 100644 index 3876d506..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/activity/EditExtractionActivity.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.activity; - -import android.app.Activity; -import android.os.Bundle; -import android.support.v4.app.NavUtils; -import android.text.TextUtils; -import android.util.SparseBooleanArray; -import android.view.*; -import android.widget.AbsListView; -import android.widget.ListView; -import android.widget.TextView; -import net.lacolaco.smileessence.Application; -import net.lacolaco.smileessence.R; -import net.lacolaco.smileessence.data.ExtractionWord; -import net.lacolaco.smileessence.logging.Logger; -import net.lacolaco.smileessence.view.DialogHelper; -import net.lacolaco.smileessence.view.adapter.CustomListAdapter; -import net.lacolaco.smileessence.view.dialog.EditTextDialogFragment; - -import java.util.ArrayList; -import java.util.List; - -public class EditExtractionActivity extends Activity implements AbsListView.MultiChoiceModeListener { - private List list; - private CustomListAdapter adapter; - - private ListView getListView() { - return (ListView) findViewById(R.id.listview_edit_list); - } - - @Override - public boolean onCreateActionMode(ActionMode mode, Menu menu) { - menu.clear(); - MenuInflater inflater = mode.getMenuInflater(); - inflater.inflate(R.menu.edit_list, menu); - return true; - } - - @Override - public boolean onPrepareActionMode(ActionMode mode, Menu menu) { - return false; - } - - @Override - public boolean onActionItemClicked(ActionMode mode, MenuItem item) { - switch (item.getItemId()) { - case R.id.menu_edit_list_delete: { - deleteSelectedItems(); - } - } - mode.finish(); - return true; - } - - @Override - public void onDestroyActionMode(ActionMode mode) { - } - - @Override - public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) { - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - Logger.debug("onCreate"); - super.onCreate(savedInstanceState); - setContentView(R.layout.layout_edit_list); - - ListView listView = getListView(); - list = new ArrayList<>(); - adapter = new CustomListAdapter() { - @Override - public View getView(int position, View convertView, ViewGroup parent) { - if (convertView == null) { - convertView = EditExtractionActivity.this.getLayoutInflater().inflate(R.layout.list_item_simple_text, null); - } - TextView textView = (TextView) convertView.findViewById(R.id.list_item_textview); - textView.setText(getItem(position).getPatternString()); - return convertView; - } - - @Override - protected List getList() { - return list; - } - }; - list.addAll(ExtractionWord.cached()); - adapter.update(); - listView.setAdapter(adapter); - listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); - listView.setMultiChoiceModeListener(this); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuItem add = menu.add(Menu.NONE, R.id.menu_edit_list_add, Menu.NONE, ""); - add.setIcon(android.R.drawable.ic_menu_add); - add.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.menu_edit_list_add: { - addNewExtractionWord(); - break; - } - case android.R.id.home: { - NavUtils.navigateUpFromSameTask(this); - return true; - } - } - return true; - } - - // -------------------------- OTHER METHODS -------------------------- - - public void deleteSelectedItems() { - SparseBooleanArray checkedItems = getListView().getCheckedItemPositions(); - for (int i = adapter.getCount() - 1; i > -1; i--) { - if (checkedItems.get(i)) { - ExtractionWord ew = adapter.getItem(i); - list.remove(ew); - ew.remove(); - } - } - adapter.update(); - } - - private void addNewExtractionWord() { - EditTextDialogFragment dialogFragment = new EditTextDialogFragment() { - @Override - public void onTextInput(String text) { - if (TextUtils.isEmpty(text.trim())) { - return; - } - ExtractionWord extractionWord = ExtractionWord.add(text); - list.add(extractionWord); - adapter.update(); - } - }; - dialogFragment.setParams(getString(R.string.dialog_title_add), ""); - dialogFragment.show(getFragmentManager(), "EDIT_TEXT"); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/activity/EditExtractionActivity.kt b/app/src/main/java/net/lacolaco/smileessence/activity/EditExtractionActivity.kt new file mode 100644 index 00000000..c621b6f7 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/activity/EditExtractionActivity.kt @@ -0,0 +1,153 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.activity + +import android.app.Activity +import android.os.Bundle +import android.support.v4.app.NavUtils +import android.text.TextUtils +import android.util.SparseBooleanArray +import android.view.* +import android.widget.AbsListView +import android.widget.ListView +import android.widget.TextView +import net.lacolaco.smileessence.Application +import net.lacolaco.smileessence.R +import net.lacolaco.smileessence.data.ExtractionWord +import net.lacolaco.smileessence.logging.Logger +import net.lacolaco.smileessence.view.DialogHelper +import net.lacolaco.smileessence.view.adapter.CustomListAdapter +import net.lacolaco.smileessence.view.dialog.EditTextDialogFragment + +import java.util.ArrayList + +class EditExtractionActivity : Activity(), AbsListView.MultiChoiceModeListener { + private lateinit var list: MutableList + private lateinit var adapter: CustomListAdapter + + private val listView: ListView + get() = findViewById(R.id.listview_edit_list) as ListView + + override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean { + menu.clear() + val inflater = mode.menuInflater + inflater.inflate(R.menu.edit_list, menu) + return true + } + + override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean { + return false + } + + override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean { + when (item.itemId) { + R.id.menu_edit_list_delete -> { + deleteSelectedItems() + } + } + mode.finish() + return true + } + + override fun onDestroyActionMode(mode: ActionMode) {} + + override fun onItemCheckedStateChanged(mode: ActionMode, position: Int, id: Long, checked: Boolean) {} + + override fun onCreate(savedInstanceState: Bundle?) { + Logger.debug("onCreate") + super.onCreate(savedInstanceState) + setContentView(R.layout.layout_edit_list) + + list = ArrayList() + adapter = object : CustomListAdapter() { + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { + var convertView = convertView + if (convertView == null) { + convertView = this@EditExtractionActivity.layoutInflater.inflate(R.layout.list_item_simple_text, null) + } + val textView = convertView!!.findViewById(R.id.list_item_textview) as TextView + textView.text = getItem(position).patternString + return convertView + } + + override val list: List + get() = this@EditExtractionActivity.list + } + list.addAll(ExtractionWord.cached()) + adapter.update() + listView.adapter = adapter + listView.choiceMode = ListView.CHOICE_MODE_MULTIPLE_MODAL + listView.setMultiChoiceModeListener(this) + } + + override fun onCreateOptionsMenu(menu: Menu): Boolean { + val add = menu.add(Menu.NONE, R.id.menu_edit_list_add, Menu.NONE, "") + add.setIcon(android.R.drawable.ic_menu_add) + add.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM) + return true + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.menu_edit_list_add -> { + addNewExtractionWord() + } + android.R.id.home -> { + NavUtils.navigateUpFromSameTask(this) + return true + } + } + return true + } + + // -------------------------- OTHER METHODS -------------------------- + + fun deleteSelectedItems() { + val checkedItems = listView.checkedItemPositions + for (i in adapter.count - 1 downTo -1 + 1) { + if (checkedItems.get(i)) { + val ew = adapter.getItem(i) + list.remove(ew) + ew.remove() + } + } + adapter.update() + } + + private fun addNewExtractionWord() { + val dialogFragment = object : EditTextDialogFragment() { + override fun onTextInput(text: String) { + if (TextUtils.isEmpty(text.trim { it <= ' ' })) { + return + } + val extractionWord = ExtractionWord.add(text) + list.add(extractionWord) + adapter.update() + } + } + dialogFragment.setParams(getString(R.string.dialog_title_add), "") + dialogFragment.show(fragmentManager, "EDIT_TEXT") + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/activity/LicenseActivity.java b/app/src/main/java/net/lacolaco/smileessence/activity/LicenseActivity.java deleted file mode 100644 index 23957c57..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/activity/LicenseActivity.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.activity; - -import android.app.Activity; -import android.os.Bundle; -import android.support.v4.app.NavUtils; -import android.view.MenuItem; -import android.widget.LinearLayout; -import android.widget.TextView; -import net.lacolaco.smileessence.Application; -import net.lacolaco.smileessence.R; - -import java.util.ArrayList; -import java.util.List; - -public class LicenseActivity extends Activity { - - // --------------------- GETTER / SETTER METHODS --------------------- - - private List getFileNames() { - List apacheFiles = new ArrayList<>(); - apacheFiles.add(getString(R.string.library_name_twitter4j)); - apacheFiles.add(getString(R.string.library_name_crouton)); - apacheFiles.add(getString(R.string.library_name_pull_to_refresh)); - apacheFiles.add(getString(R.string.library_name_volley)); - apacheFiles.add(getString(R.string.library_name_twitter_text)); - return apacheFiles; - } - - // ------------------------ OVERRIDE METHODS ------------------------ - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.layout_license); - - setFiles(); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: { - NavUtils.navigateUpFromSameTask(this); - return true; - } - } - return true; - } - - private void setFiles() { - LinearLayout files = (LinearLayout) findViewById(R.id.linear_license_files); - List apacheFiles = getFileNames(); - for (String apacheFile : apacheFiles) { - TextView name = new TextView(this); - name.setText(String.format("- %s", apacheFile)); - files.addView(name); - } - } -} \ No newline at end of file diff --git a/app/src/main/java/net/lacolaco/smileessence/activity/LicenseActivity.kt b/app/src/main/java/net/lacolaco/smileessence/activity/LicenseActivity.kt new file mode 100644 index 00000000..58bcc08c --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/activity/LicenseActivity.kt @@ -0,0 +1,81 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.activity + +import android.app.Activity +import android.os.Bundle +import android.support.v4.app.NavUtils +import android.view.MenuItem +import android.widget.LinearLayout +import android.widget.TextView +import net.lacolaco.smileessence.Application +import net.lacolaco.smileessence.R + +import java.util.ArrayList + +class LicenseActivity : Activity() { + + // --------------------- GETTER / SETTER METHODS --------------------- + + private val fileNames: List + get() { + val apacheFiles = ArrayList() + apacheFiles.add(getString(R.string.library_name_twitter4j)) + apacheFiles.add(getString(R.string.library_name_crouton)) + apacheFiles.add(getString(R.string.library_name_pull_to_refresh)) + apacheFiles.add(getString(R.string.library_name_volley)) + apacheFiles.add(getString(R.string.library_name_twitter_text)) + return apacheFiles + } + + // ------------------------ OVERRIDE METHODS ------------------------ + + public override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.layout_license) + + setFiles() + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + android.R.id.home -> { + NavUtils.navigateUpFromSameTask(this) + return true + } + } + return true + } + + private fun setFiles() { + val files = findViewById(R.id.linear_license_files) as LinearLayout + val apacheFiles = fileNames + for (apacheFile in apacheFiles) { + val name = TextView(this) + name.text = String.format("- %s", apacheFile) + files.addView(name) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/lacolaco/smileessence/activity/MainActivity.java b/app/src/main/java/net/lacolaco/smileessence/activity/MainActivity.java deleted file mode 100644 index 4997f3f1..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/activity/MainActivity.java +++ /dev/null @@ -1,347 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.activity; - -import android.app.ActionBar; -import android.app.Activity; -import android.app.ActivityManager; -import android.content.Intent; -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.provider.MediaStore; -import android.support.v4.view.ViewPager; -import android.view.Menu; -import android.view.MenuItem; -import android.view.WindowManager; -import android.widget.ImageView; -import de.keyboardsurfer.android.widget.crouton.Crouton; -import net.lacolaco.smileessence.*; -import net.lacolaco.smileessence.data.Account; -import net.lacolaco.smileessence.data.ExtractionWord; -import net.lacolaco.smileessence.entity.RBinding; -import net.lacolaco.smileessence.entity.User; -import net.lacolaco.smileessence.logging.Logger; -import net.lacolaco.smileessence.twitter.task.Users; -import net.lacolaco.smileessence.util.BitmapOptimizer; -import net.lacolaco.smileessence.util.BitmapURLTask; -import net.lacolaco.smileessence.util.IntentUtils; -import net.lacolaco.smileessence.util.UIObserverBundle; -import net.lacolaco.smileessence.view.adapter.PageListAdapter; -import net.lacolaco.smileessence.view.dialog.ConfirmDialogFragment; -import net.lacolaco.smileessence.view.page.*; - -import java.lang.reflect.Field; - -public class MainActivity extends Activity implements ViewPager.OnPageChangeListener { - public static final int REQUEST_GET_PICTURE_FROM_GALLERY = 11; - private final UIObserverBundle currentUserBundle = new UIObserverBundle(); - private World world; - private ViewPager viewPager; - private ImageView currentAccountIconImageView; - private PageListAdapter pagerAdapter; - - public World getWorld() { - return world; - } - - private void setSelectedPageIndex(int position) { - setSelectedPageIndex(position, true); - } - - private void setSelectedPageIndex(int position, boolean smooth) { - viewPager.setCurrentItem(position, smooth); - } - - public void openHomePage() { - setSelectedPageIndex(pagerAdapter.getIndex(HomeFragment.class)); - } - - public void openPostPage() { - setSelectedPageIndex(pagerAdapter.getIndex(PostFragment.class)); - } - - public void openPostPageWithImage(Uri uri) { - try { - Cursor c = getContentResolver().query(uri, null, null, null, null); - assert c != null; - c.moveToFirst(); - String path = c.getString(c.getColumnIndex(MediaStore.MediaColumns.DATA)); - String rotatedPath = path; // BitmapOptimizer.rotateImageByExif(this, path); - world.getPostState().beginTransaction() - .setMediaFilePath(rotatedPath) - .commitWithOpen(this); - world.notify(R.string.notice_select_image_succeeded); - c.close(); - } catch (Exception e) { - e.printStackTrace(); - world.notifyError(R.string.notice_select_image_failed); - } - } - - public void openSearchPage(String query) { - SearchFragment fragment = (SearchFragment) pagerAdapter.getCachedFragment(pagerAdapter.getIndex(SearchFragment.class)); - if (fragment != null) { - fragment.startSearch(query); - setSelectedPageIndex(pagerAdapter.getIndex(SearchFragment.class)); - } - } - - public void openUserListPage(String listFullName) { - UserListFragment fragment = (UserListFragment) pagerAdapter.getCachedFragment(pagerAdapter.getIndex(UserListFragment.class)); - if (fragment != null) { - fragment.startUserList(listFullName); - setSelectedPageIndex(pagerAdapter.getIndex(UserListFragment.class)); - } - } - - // ------------------------ OVERRIDE METHODS ------------------------ - - @Override - public void onBackPressed() { - this.finish(); - } - - @Override - public void finish() { - if (viewPager == null) { - super.finish(); - return; - } - int homeIndex = pagerAdapter.getIndex(HomeFragment.class); - if (viewPager.getCurrentItem() != homeIndex) { - viewPager.setCurrentItem(homeIndex, true); - } else { - ConfirmDialogFragment.show(this, getString(R.string.dialog_confirm_finish_app), super::finish); - } - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode) { - case REQUEST_GET_PICTURE_FROM_GALLERY: - getImageUri(requestCode, resultCode, data); - break; - } - } - - @Override - public void onCreate(Bundle savedInstanceState) { - Logger.debug("onCreate"); - super.onCreate(savedInstanceState); - - Uri uri = getIntent().getData(); - if (uri == null) { - throw new IllegalStateException("[BUG] data not set"); - } - String userIdValue = uri.getQueryParameter("user_id"); - if (userIdValue == null) - throw new IllegalStateException("[BUG] user_id not set"); - long userId = Long.parseLong(userIdValue); - world = Application.getWorld(userId); - world.setMainActivity(this); - - // XXX - Account account = world.getAccount(); - - setTheme(account.themeIndex == 0 ? R.style.theme_dark : R.style.theme_light); - setContentView(R.layout.layout_main); - - viewPager = (ViewPager) findViewById(R.id.viewPager); - pagerAdapter = new PageListAdapter(this); - viewPager.addOnPageChangeListener(this); - getActionBar().setDisplayHomeAsUpEnabled(true); - currentAccountIconImageView = (ImageView) findViewById(android.R.id.home); - currentAccountIconImageView.setScaleType(ImageView.ScaleType.FIT_XY); - - // TODO: tab order? - Bundle args = new Bundle(); - args.putLong(PageFragment.KEY_USER_ID, account.getUserId()); - pagerAdapter.addPage(PostFragment.class, getString(R.string.page_name_post), args, false); - pagerAdapter.addPage(HomeFragment.class, getString(R.string.page_name_home), args, false); - pagerAdapter.addPage(MentionsFragment.class, getString(R.string.page_name_mentions), args, false); - pagerAdapter.addPage(HistoryFragment.class, getString(R.string.page_name_history), args, false); - pagerAdapter.addPage(MessagesFragment.class, getString(R.string.page_name_messages), args, false); - pagerAdapter.addPage(SearchFragment.class, getString(R.string.page_name_search), args, false); - pagerAdapter.addPage(UserListFragment.class, getString(R.string.page_name_list), args, false); - pagerAdapter.notifyDataSetChanged(); - viewPager.setOffscreenPageLimit(pagerAdapter.getCount()); - viewPager.setAdapter(pagerAdapter); - setSelectedPageIndex(pagerAdapter.getIndex(HomeFragment.class), false); - - ExtractionWord.load(); - - // update cache - world.refreshListSubscriptions(); - world.refreshUserMuteList(); - world.refreshSavedSearches(); - new Users.GetTask(account, account.getUserId()).execute(); - - User user = account.getUser(); - - // Set application title - setTitle(); - - // update actionbar - Runnable update = () -> { - setTitle(); - updateActionBarTitle(); - String newUrl = user.getProfileImageUrlOriginal(); - if (newUrl != null) { - new BitmapURLTask(newUrl, currentAccountIconImageView).execute(); - } - }; - update.run(); //first run - - currentUserBundle.detachAll(); - currentUserBundle.attach(user, changes -> { - if (changes.contains(RBinding.BASIC)) update.run(); - }); - - // refresh all pages - for (int i = 0; i < pagerAdapter.getCount(); ++i) { - PageFragment pf = pagerAdapter.getCachedFragment(i); - if (pf != null && pf.isAdded()) { - Logger.debug(String.format("PageFragment %s is already attached; refreshing", pf.getClass().getName())); - pf.refresh(); - } - } - - // start user stream - world.setupStreaming(); - } - - private void setTitle() { - String label = getString(R.string.app_name) + " - @" + world.getAccount().getUser().getScreenName(); - ActivityManager.TaskDescription desc = new ActivityManager.TaskDescription(label); - setTaskDescription(desc); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - currentUserBundle.detachAll(); - Crouton.cancelAllCroutons(); - // Workaround for LeakCanary - fixCroutonLeak(); - Logger.debug("onDestroy"); - } - - private void fixCroutonLeak() { - try { - Class klass = Class.forName("de.keyboardsurfer.android.widget.crouton.DefaultAnimationsBuilder"); - Field slideInDownAnimation = klass.getDeclaredField("slideInDownAnimation"); - slideInDownAnimation.setAccessible(true); - slideInDownAnimation.set(null, null); - Field slideOutUpAnimation = klass.getDeclaredField("slideOutUpAnimation"); - slideOutUpAnimation.setAccessible(true); - slideOutUpAnimation.set(null, null); - } catch (Exception e) { - Logger.error("crouton fix error: " + e); - } - } - - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.main, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: { - Intent intent = new Intent(this, ManageAccountsActivity.class); - intent.putExtra(ManageAccountsActivity.INTENT_KEY_NOINIT, true); - startActivity(intent); - return true; - } - case R.id.actionbar_setting: - startActivity(new Intent(this, SettingActivity.class)); - return true; - case R.id.actionbar_edit_extraction: - startActivity(new Intent(this, EditExtractionActivity.class)); - return true; - case R.id.actionbar_aclog: - IntentUtils.openUri(this, world.getAccount().getUser().getAclogTimelineURL()); - return true; - default: - return super.onOptionsItemSelected(item); - } - } - - @Override - protected void onPause() { - Logger.debug("onPause"); - super.onPause(); - world.setMainActivityActive(false); - } - - @Override - protected void onResume() { - Logger.debug("onResume"); - super.onResume(); - world.setMainActivityActive(true); - } - - // --------------------- Interface OnPageChangeListener --------------------- - - @Override - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { - } - - @Override - public void onPageSelected(int position) { - Logger.debug("Page selected: " + position); - updateActionBarTitle(); - } - - @Override - public void onPageScrollStateChanged(int state) { - } - - // -------------------------- OTHER METHODS -------------------------- - - private void getImageUri(int requestCode, int resultCode, Intent data) { - if (resultCode != RESULT_OK) { - Logger.error(requestCode); - world.notifyError(R.string.notice_select_image_failed); - finish(); - return; - } - openPostPageWithImage(data.getData()); - } - - private void updateActionBarTitle() { - ActionBar actionBar = getActionBar(); - Account currentAccount = world.getAccount(); - if (actionBar != null) { - String screenName = currentAccount.getUser().getScreenName(); - String pageTitle = pagerAdapter.getName(viewPager.getCurrentItem()); - setTitle(String.format("%s / %s", screenName, pageTitle)); - } - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/activity/MainActivity.kt b/app/src/main/java/net/lacolaco/smileessence/activity/MainActivity.kt new file mode 100644 index 00000000..8b8da33f --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/activity/MainActivity.kt @@ -0,0 +1,311 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.activity + +import android.app.Activity +import android.app.ActivityManager +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import android.provider.MediaStore +import android.support.v4.view.ViewPager +import android.view.Menu +import android.view.MenuItem +import android.widget.ImageView +import de.keyboardsurfer.android.widget.crouton.Crouton +import net.lacolaco.smileessence.* +import net.lacolaco.smileessence.data.ExtractionWord +import net.lacolaco.smileessence.entity.RBinding +import net.lacolaco.smileessence.logging.Logger +import net.lacolaco.smileessence.twitter.task.Users +import net.lacolaco.smileessence.util.BitmapURLTask +import net.lacolaco.smileessence.util.IntentUtils +import net.lacolaco.smileessence.util.UIObserverBundle +import net.lacolaco.smileessence.view.adapter.PageListAdapter +import net.lacolaco.smileessence.view.dialog.ConfirmDialogFragment +import net.lacolaco.smileessence.view.page.* + +class MainActivity : Activity(), ViewPager.OnPageChangeListener { + private val currentUserBundle = UIObserverBundle() + val world: World by lazy { + val uri = intent.data ?: throw IllegalStateException("[BUG] data not set") + val userIdValue = uri.getQueryParameter("user_id") ?: throw IllegalStateException("[BUG] user_id not set") + val userId = java.lang.Long.parseLong(userIdValue) + Application.getWorld(userId) + } + private lateinit var viewPager: ViewPager + private lateinit var pagerAdapter: PageListAdapter + private lateinit var currentAccountIconImageView: ImageView + + private fun setSelectedPageIndex(position: Int, smooth: Boolean = true) { + viewPager.setCurrentItem(position, smooth) + } + + fun openHomePage() { + setSelectedPageIndex(pagerAdapter.getIndex(HomeFragment::class.java)) + } + + fun openPostPage() { + setSelectedPageIndex(pagerAdapter.getIndex(PostFragment::class.java)) + } + + fun openPostPageWithImage(uri: Uri) { + try { + val c = contentResolver.query(uri, null, null, null, null) + assert(c != null) + c!!.moveToFirst() + val path = c.getString(c.getColumnIndex(MediaStore.MediaColumns.DATA)) + world.postState.beginTransaction() + .setMediaFilePath(path) + .commitWithOpen(this) + world.notify(R.string.notice_select_image_succeeded) + c.close() + } catch (e: Exception) { + e.printStackTrace() + world.notifyError(R.string.notice_select_image_failed) + } + + } + + fun openSearchPage(query: String) { + val fragment = pagerAdapter.getCachedFragment(pagerAdapter.getIndex(SearchFragment::class.java)) as SearchFragment? + if (fragment != null) { + fragment.startSearch(query) + setSelectedPageIndex(pagerAdapter.getIndex(SearchFragment::class.java)) + } + } + + fun openUserListPage(listFullName: String) { + val fragment = pagerAdapter.getCachedFragment(pagerAdapter.getIndex(UserListFragment::class.java)) as UserListFragment? + if (fragment != null) { + fragment.startUserList(listFullName) + setSelectedPageIndex(pagerAdapter.getIndex(UserListFragment::class.java)) + } + } + + // ------------------------ OVERRIDE METHODS ------------------------ + + override fun onBackPressed() { + this.finish() + } + + override fun finish() { + val homeIndex = pagerAdapter.getIndex(HomeFragment::class.java) + if (viewPager.currentItem != homeIndex) { + viewPager.setCurrentItem(homeIndex, true) + } else { + ConfirmDialogFragment.show(this, getString(R.string.dialog_confirm_finish_app)) { super.finish() } + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + when (requestCode) { + REQUEST_GET_PICTURE_FROM_GALLERY -> getImageUri(requestCode, resultCode, data) + } + } + + public override fun onCreate(savedInstanceState: Bundle?) { + Logger.debug("onCreate") + super.onCreate(savedInstanceState) + + world.setMainActivity(this) + + // XXX + val account = world.account + + setTheme(if (account.themeIndex == 0) R.style.theme_dark else R.style.theme_light) + setContentView(R.layout.layout_main) + + viewPager = findViewById(R.id.viewPager) as ViewPager + pagerAdapter = PageListAdapter(this) + viewPager.addOnPageChangeListener(this) + actionBar.setDisplayHomeAsUpEnabled(true) + currentAccountIconImageView = findViewById(android.R.id.home) as ImageView + currentAccountIconImageView.scaleType = ImageView.ScaleType.FIT_XY + + // TODO: tab order? + val args = Bundle() + args.putLong(PageFragment.KEY_USER_ID, account.userId) + pagerAdapter.addPage(PostFragment::class.java, getString(R.string.page_name_post), args, false) + pagerAdapter.addPage(HomeFragment::class.java, getString(R.string.page_name_home), args, false) + pagerAdapter.addPage(MentionsFragment::class.java, getString(R.string.page_name_mentions), args, false) + pagerAdapter.addPage(HistoryFragment::class.java, getString(R.string.page_name_history), args, false) + pagerAdapter.addPage(MessagesFragment::class.java, getString(R.string.page_name_messages), args, false) + pagerAdapter.addPage(SearchFragment::class.java, getString(R.string.page_name_search), args, false) + pagerAdapter.addPage(UserListFragment::class.java, getString(R.string.page_name_list), args, false) + pagerAdapter.notifyDataSetChanged() + viewPager.offscreenPageLimit = pagerAdapter.count + viewPager.adapter = pagerAdapter + setSelectedPageIndex(pagerAdapter.getIndex(HomeFragment::class.java), false) + + ExtractionWord.load() + + // update cache + world.refreshListSubscriptions() + world.refreshUserMuteList() + world.refreshSavedSearches() + Users.GetTask(account, account.userId).execute() + + val user = account.user + + // Set application title + setTitle() + + // update actionbar + val update = { + setTitle() + updateActionBarTitle() + val newUrl = user.profileImageUrl + if (newUrl != null) { + BitmapURLTask(newUrl, currentAccountIconImageView).execute() + } + } + update() //first run + + currentUserBundle.detachAll() + currentUserBundle.attach(user) { changes -> if (changes.contains(RBinding.BASIC)) update() } + + // refresh all pages + for (i in 0..pagerAdapter.count - 1) { + val pf = pagerAdapter.getCachedFragment(i) + if (pf != null && pf.isAdded) { + Logger.debug(String.format("PageFragment %s is already attached; refreshing", pf.javaClass.name)) + pf.refresh() + } + } + + // start user stream + world.setupStreaming() + } + + private fun setTitle() { + val label = getString(R.string.app_name) + " - @" + world.account.user.screenName + val desc = ActivityManager.TaskDescription(label) + setTaskDescription(desc) + } + + override fun onDestroy() { + super.onDestroy() + currentUserBundle.detachAll() + Crouton.cancelAllCroutons() + // Workaround for LeakCanary + fixCroutonLeak() + Logger.debug("onDestroy") + } + + private fun fixCroutonLeak() { + try { + val klass = Class.forName("de.keyboardsurfer.android.widget.crouton.DefaultAnimationsBuilder") + val slideInDownAnimation = klass.getDeclaredField("slideInDownAnimation") + slideInDownAnimation.isAccessible = true + slideInDownAnimation.set(null, null) + val slideOutUpAnimation = klass.getDeclaredField("slideOutUpAnimation") + slideOutUpAnimation.isAccessible = true + slideOutUpAnimation.set(null, null) + } catch (e: Exception) { + Logger.error("crouton fix error: " + e) + } + + } + + + override fun onCreateOptionsMenu(menu: Menu): Boolean { + menuInflater.inflate(R.menu.main, menu) + return true + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + android.R.id.home -> { + val intent = Intent(this, ManageAccountsActivity::class.java) + intent.putExtra(ManageAccountsActivity.INTENT_KEY_NOINIT, true) + startActivity(intent) + return true + } + R.id.actionbar_setting -> { + startActivity(Intent(this, SettingActivity::class.java)) + return true + } + R.id.actionbar_edit_extraction -> { + startActivity(Intent(this, EditExtractionActivity::class.java)) + return true + } + R.id.actionbar_aclog -> { + IntentUtils.openUri(this, world.account.user.aclogTimelineURL) + return true + } + else -> return super.onOptionsItemSelected(item) + } + } + + override fun onPause() { + Logger.debug("onPause") + super.onPause() + world.setMainActivityActive(false) + } + + override fun onResume() { + Logger.debug("onResume") + super.onResume() + world.setMainActivityActive(true) + } + + // --------------------- Interface OnPageChangeListener --------------------- + + override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {} + + override fun onPageSelected(position: Int) { + Logger.debug("Page selected: " + position) + updateActionBarTitle() + } + + override fun onPageScrollStateChanged(state: Int) {} + + // -------------------------- OTHER METHODS -------------------------- + + private fun getImageUri(requestCode: Int, resultCode: Int, data: Intent?) { + if (resultCode != Activity.RESULT_OK) { + Logger.error(requestCode) + world.notifyError(R.string.notice_select_image_failed) + finish() + return + } + openPostPageWithImage(data!!.data) + } + + private fun updateActionBarTitle() { + val actionBar = actionBar + val currentAccount = world.account + if (actionBar != null) { + val screenName = currentAccount.user.screenName + val pageTitle = pagerAdapter.getName(viewPager.currentItem) + title = String.format("%s / %s", screenName, pageTitle) + } + } + + companion object { + val REQUEST_GET_PICTURE_FROM_GALLERY = 11 + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/activity/ManageAccountsActivity.java b/app/src/main/java/net/lacolaco/smileessence/activity/ManageAccountsActivity.java deleted file mode 100644 index af891fec..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/activity/ManageAccountsActivity.java +++ /dev/null @@ -1,257 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.activity; - -import android.app.Activity; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.net.Uri; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.app.ActivityCompat; -import android.support.v4.content.ContextCompat; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.*; -import com.android.volley.toolbox.NetworkImageView; -import net.lacolaco.smileessence.Application; -import net.lacolaco.smileessence.R; -import net.lacolaco.smileessence.World; -import net.lacolaco.smileessence.data.Account; -import net.lacolaco.smileessence.data.ImageCache; -import net.lacolaco.smileessence.logging.Logger; -import net.lacolaco.smileessence.twitter.OAuthSession; -import net.lacolaco.smileessence.view.dialog.ConfirmDialogFragment; - -import java.util.ArrayList; -import java.util.List; - -public class ManageAccountsActivity extends Activity implements AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener { - public static final String INTENT_KEY_NOINIT = "noInit"; - private static final int REQUEST_OAUTH = 10; - private static final int REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION = 11; - private EditAccountsAdapter adapter; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - // Check if it is initiated from launcher - if (!getIntent().getBooleanExtra(INTENT_KEY_NOINIT, false)) { - int wextPermission = ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE); - if (wextPermission != PackageManager.PERMISSION_GRANTED) { - ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION); - } - - // Skip this activity if app is already started - World currentWorld = Application.getCurrentWorld(); - if (currentWorld != null) { - goToWorld(currentWorld); - return; - } - } - - setContentView(R.layout.layout_edit_list); - adapter = new EditAccountsAdapter(); - ListView listView = (ListView) findViewById(R.id.listview_edit_list); - listView.setAdapter(adapter); - listView.setOnItemClickListener(this); - listView.setOnItemLongClickListener(this); - } - - @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) { - switch (requestCode) { - case REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION: { - if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - // OK - World currentWorld = Application.getCurrentWorld(); - if (currentWorld != null) { - goToWorld(currentWorld); - } - } else { - Application.toast(R.string.notice_error_storage_permission); - // TODO: Kill Process? - finish(); - } - break; - } - } - } - - private void goToWorld(World world) { - // Continue the existing MainActivity - Intent intent = new Intent(this, MainActivity.class); - intent.setData(Uri.parse("smileessence://mainactivity/?user_id=" + world.getAccount().getUserId())); - finish(); - startActivity(intent); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuItem add = menu.add(Menu.NONE, R.id.menu_edit_list_add, Menu.NONE, ""); - add.setIcon(android.R.drawable.ic_menu_add); - add.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); - return true; - } - - @Override - public void onItemClick(AdapterView adapterView, View view, int i, long l) { - Account account = adapter.getItem(i); - goToWorld(Application.getWorld(account.getUserId())); - } - - @Override - public boolean onItemLongClick(AdapterView adapterView, View view, int i, long l) { - if (adapter.getCount() > 1) { - // remove account from application - Account account = adapter.getItem(i); - ConfirmDialogFragment.show(this, getString(R.string.dialog_confirm_clear_account, account.getUser().getScreenName()), () -> { - adapter.removeAt(i); - Account.unregister(account.getUserId()); - }, false); - return true; - } else { - Application.toast(R.string.notice_cant_remove_last_account); - return false; - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.menu_edit_list_add: { - startActivityForResult(new Intent(this, OAuthActivity.class), REQUEST_OAUTH); - break; - } - case android.R.id.home: { - safeFinish(); - } - } - return true; - } - - @Override - public void onBackPressed() { - safeFinish(); - } - - private void safeFinish() { - World currentWorld = Application.getCurrentWorld(); - - if (currentWorld != null) { - goToWorld(currentWorld); - } else { - setResult(RESULT_CANCELED); - finish(); - } - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode) { - case REQUEST_OAUTH: { - receiveOAuth(requestCode, resultCode, data); - break; - } - default: { - Logger.error("[BUG] unexpected activity result: reqCode=" + requestCode + ", resCode=" + resultCode); - break; - } - } - } - - private void receiveOAuth(int requestCode, int resultCode, Intent data) { - if (resultCode == RESULT_OK) { - Account account = Account.register(data.getStringExtra(OAuthSession.KEY_TOKEN), - data.getStringExtra(OAuthSession.KEY_TOKEN_SECRET), - data.getLongExtra(OAuthSession.KEY_USER_ID, -1L), - data.getStringExtra(OAuthSession.KEY_SCREEN_NAME)); - adapter.add(account); - } else { - Logger.error(requestCode); - Application.toast(R.string.notice_error_authenticate); - } - } - - private class EditAccountsAdapter extends BaseAdapter { - private final List accounts; - - public EditAccountsAdapter() { - accounts = new ArrayList<>(Account.all()); - } - - @Override - public int getCount() { - return accounts.size(); - } - - @Override - public Account getItem(int position) { - return accounts.get(position); - } - - @Override - public long getItemId(int position) { - return accounts.get(position).getUserId(); - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - if (convertView == null) { - convertView = getLayoutInflater().inflate(R.layout.list_item_account, null); - } - Account account = getItem(position); - NetworkImageView iconView = (NetworkImageView) convertView.findViewById(R.id.account_icon); - iconView.setImageUrl(account.getUser().getProfileImageUrlOriginal(), ImageCache.getImageLoader()); - - TextView textView = (TextView) convertView.findViewById(R.id.account_text_view); - String text = "@" + account.getUser().getScreenName(); - textView.setText(text); - - return convertView; - } - - public int add(Account account) { - if (!accounts.contains(account)) { - accounts.add(account); - notifyDataSetChanged(); - return accounts.size() - 1; - } else { - return accounts.indexOf(account); - } - } - - public Account removeAt(int position) { - Account account = accounts.remove(position); - if (account != null) { - notifyDataSetChanged(); - } - return account; - } - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/activity/ManageAccountsActivity.kt b/app/src/main/java/net/lacolaco/smileessence/activity/ManageAccountsActivity.kt new file mode 100644 index 00000000..2ef184fc --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/activity/ManageAccountsActivity.kt @@ -0,0 +1,241 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.activity + +import android.app.Activity +import android.content.Intent +import android.content.pm.PackageManager +import android.net.Uri +import android.os.Bundle +import android.support.v4.app.ActivityCompat +import android.support.v4.content.ContextCompat +import android.view.Menu +import android.view.MenuItem +import android.view.View +import android.view.ViewGroup +import android.widget.* +import com.android.volley.toolbox.NetworkImageView +import net.lacolaco.smileessence.Application +import net.lacolaco.smileessence.R +import net.lacolaco.smileessence.World +import net.lacolaco.smileessence.data.Account +import net.lacolaco.smileessence.data.ImageCache +import net.lacolaco.smileessence.logging.Logger +import net.lacolaco.smileessence.twitter.OAuthSession +import net.lacolaco.smileessence.view.dialog.ConfirmDialogFragment + +import java.util.ArrayList + +class ManageAccountsActivity : Activity(), AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener { + private var adapter: EditAccountsAdapter? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + // Check if it is initiated from launcher + if (!intent.getBooleanExtra(INTENT_KEY_NOINIT, false)) { + val wextPermission = ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) + if (wextPermission != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.WRITE_EXTERNAL_STORAGE), REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION) + } + + // Skip this activity if app is already started + val currentWorld = Application.currentWorld + if (currentWorld != null) { + goToWorld(currentWorld) + return + } + } + + setContentView(R.layout.layout_edit_list) + adapter = EditAccountsAdapter() + val listView = findViewById(R.id.listview_edit_list) as ListView + listView.adapter = adapter + listView.onItemClickListener = this + listView.onItemLongClickListener = this + } + + override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { + when (requestCode) { + REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION -> { + if (grantResults.size > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + // OK + val currentWorld = Application.currentWorld + if (currentWorld != null) { + goToWorld(currentWorld) + } + } else { + Application.toast(R.string.notice_error_storage_permission) + // TODO: Kill Process? + finish() + } + } + } + } + + private fun goToWorld(world: World) { + // Continue the existing MainActivity + val intent = Intent(this, MainActivity::class.java) + intent.data = Uri.parse("smileessence://mainactivity/?user_id=" + world.account.userId) + finish() + startActivity(intent) + } + + override fun onCreateOptionsMenu(menu: Menu): Boolean { + val add = menu.add(Menu.NONE, R.id.menu_edit_list_add, Menu.NONE, "") + add.setIcon(android.R.drawable.ic_menu_add) + add.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM) + return true + } + + override fun onItemClick(adapterView: AdapterView<*>, view: View, i: Int, l: Long) { + val account = adapter!!.getItem(i) + goToWorld(Application.getWorld(account.userId)) + } + + override fun onItemLongClick(adapterView: AdapterView<*>, view: View, i: Int, l: Long): Boolean { + if (adapter!!.count > 1) { + // remove account from application + val account = adapter!!.getItem(i) + ConfirmDialogFragment.show(this, getString(R.string.dialog_confirm_clear_account, account.user.screenName), { + adapter!!.removeAt(i) + Account.unregister(account.userId) + }, false) + return true + } else { + Application.toast(R.string.notice_cant_remove_last_account) + return false + } + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.menu_edit_list_add -> { + startActivityForResult(Intent(this, OAuthActivity::class.java), REQUEST_OAUTH) + } + android.R.id.home -> { + safeFinish() + } + } + return true + } + + override fun onBackPressed() { + safeFinish() + } + + private fun safeFinish() { + val currentWorld = Application.currentWorld + + if (currentWorld != null) { + goToWorld(currentWorld) + } else { + setResult(Activity.RESULT_CANCELED) + finish() + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) { + when (requestCode) { + REQUEST_OAUTH -> { + receiveOAuth(requestCode, resultCode, data) + } + else -> { + Logger.error("[BUG] unexpected activity result: reqCode=$requestCode, resCode=$resultCode") + } + } + } + + private fun receiveOAuth(requestCode: Int, resultCode: Int, data: Intent) { + if (resultCode == Activity.RESULT_OK) { + val account = Account.register(data.getStringExtra(OAuthSession.KEY_TOKEN), + data.getStringExtra(OAuthSession.KEY_TOKEN_SECRET), + data.getLongExtra(OAuthSession.KEY_USER_ID, -1L), + data.getStringExtra(OAuthSession.KEY_SCREEN_NAME)) + adapter!!.add(account) + } else { + Logger.error(requestCode) + Application.toast(R.string.notice_error_authenticate) + } + } + + private inner class EditAccountsAdapter : BaseAdapter() { + private val accounts: MutableList + + init { + accounts = ArrayList(Account.all()) + } + + override fun getCount(): Int { + return accounts.size + } + + override fun getItem(position: Int): Account { + return accounts[position] + } + + override fun getItemId(position: Int): Long { + return accounts[position].userId + } + + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { + var convertView = convertView + if (convertView == null) { + convertView = layoutInflater.inflate(R.layout.list_item_account, null) + } + val account = getItem(position) + val iconView = convertView!!.findViewById(R.id.account_icon) as NetworkImageView + iconView.setImageUrl(account.user.profileImageUrl, ImageCache.getImageLoader()) + + val textView = convertView.findViewById(R.id.account_text_view) as TextView + val text = "@" + account.user.screenName + textView.text = text + + return convertView + } + + fun add(account: Account): Int { + if (!accounts.contains(account)) { + accounts.add(account) + notifyDataSetChanged() + return accounts.size - 1 + } else { + return accounts.indexOf(account) + } + } + + fun removeAt(position: Int): Account? { + val account = accounts.removeAt(position) + notifyDataSetChanged() + return account + } + } + + companion object { + val INTENT_KEY_NOINIT = "noInit" + private val REQUEST_OAUTH = 10 + private val REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION = 11 + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/activity/OAuthActivity.java b/app/src/main/java/net/lacolaco/smileessence/activity/OAuthActivity.java deleted file mode 100644 index e3d15bc2..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/activity/OAuthActivity.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.activity; - -import android.app.Activity; -import android.content.Intent; -import android.os.Bundle; -import android.text.Editable; -import android.text.TextUtils; -import android.text.TextWatcher; -import android.view.View; -import android.widget.Button; -import android.widget.EditText; -import android.widget.TextView; -import net.lacolaco.smileessence.Application; -import net.lacolaco.smileessence.R; -import net.lacolaco.smileessence.twitter.OAuthSession; -import twitter4j.auth.AccessToken; - -public class OAuthActivity extends Activity implements View.OnClickListener, TextWatcher { - private EditText pinEditText; - private Button authButton; - private OAuthSession oauthSession; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.layout_oauth); - - TextView linkTextView = (TextView) findViewById(R.id.textView_oauth_link); - pinEditText = (EditText) findViewById(R.id.editText_oauth_pin); - pinEditText.addTextChangedListener(this); - authButton = (Button) findViewById(R.id.button_oauth_auth); - authButton.setOnClickListener(this); - authButton.setEnabled(false); - - oauthSession = new OAuthSession(); - String url = oauthSession.getAuthorizationURL(); - if (!TextUtils.isEmpty(url)) { - linkTextView.setText(url); - } else { - Application.toast(R.string.notice_error_authenticate_request); - finish(); - } - } - - @Override - public void onClick(View v) { - switch (v.getId()) { - case R.id.button_oauth_auth: { - AccessToken accessToken = oauthSession.getAccessToken(pinEditText.getText().toString()); - if (accessToken != null) { - Intent intent = new Intent(); - intent.putExtra(OAuthSession.KEY_TOKEN, accessToken.getToken()); - intent.putExtra(OAuthSession.KEY_TOKEN_SECRET, accessToken.getTokenSecret()); - intent.putExtra(OAuthSession.KEY_USER_ID, accessToken.getUserId()); - intent.putExtra(OAuthSession.KEY_SCREEN_NAME, accessToken.getScreenName()); - setResult(RESULT_OK, intent); - finish(); - } else { - setResult(RESULT_CANCELED); - finish(); - } - } - } - } - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - authButton.setEnabled(s.length() > 0); - } - - @Override - public void afterTextChanged(Editable s) { - } -} \ No newline at end of file diff --git a/app/src/main/java/net/lacolaco/smileessence/activity/OAuthActivity.kt b/app/src/main/java/net/lacolaco/smileessence/activity/OAuthActivity.kt new file mode 100644 index 00000000..c2388bbf --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/activity/OAuthActivity.kt @@ -0,0 +1,95 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.activity + +import android.app.Activity +import android.content.Intent +import android.os.Bundle +import android.text.Editable +import android.text.TextUtils +import android.text.TextWatcher +import android.view.View +import android.widget.Button +import android.widget.EditText +import android.widget.TextView +import net.lacolaco.smileessence.Application +import net.lacolaco.smileessence.R +import net.lacolaco.smileessence.twitter.OAuthSession +import twitter4j.auth.AccessToken + +class OAuthActivity : Activity(), View.OnClickListener, TextWatcher { + private lateinit var pinEditText: EditText + private lateinit var authButton: Button + private lateinit var oauthSession: OAuthSession + + public override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.layout_oauth) + + val linkTextView = findViewById(R.id.textView_oauth_link) as TextView + pinEditText = findViewById(R.id.editText_oauth_pin) as EditText + pinEditText.addTextChangedListener(this) + authButton = findViewById(R.id.button_oauth_auth) as Button + authButton.setOnClickListener(this) + authButton.isEnabled = false + + oauthSession = OAuthSession() + val url = oauthSession.authorizationURL + if (!TextUtils.isEmpty(url)) { + linkTextView.text = url + } else { + Application.toast(R.string.notice_error_authenticate_request) + finish() + } + } + + override fun onClick(v: View) { + when (v.id) { + R.id.button_oauth_auth -> { + val accessToken = oauthSession.getAccessToken(pinEditText.text.toString()) + if (accessToken != null) { + val intent = Intent() + intent.putExtra(OAuthSession.KEY_TOKEN, accessToken.token) + intent.putExtra(OAuthSession.KEY_TOKEN_SECRET, accessToken.tokenSecret) + intent.putExtra(OAuthSession.KEY_USER_ID, accessToken.userId) + intent.putExtra(OAuthSession.KEY_SCREEN_NAME, accessToken.screenName) + setResult(Activity.RESULT_OK, intent) + finish() + } else { + setResult(Activity.RESULT_CANCELED) + finish() + } + } + } + } + + override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {} + + override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { + authButton.isEnabled = s.length > 0 + } + + override fun afterTextChanged(s: Editable) {} +} \ No newline at end of file diff --git a/app/src/main/java/net/lacolaco/smileessence/activity/SettingActivity.java b/app/src/main/java/net/lacolaco/smileessence/activity/SettingActivity.java deleted file mode 100644 index 87f44e16..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/activity/SettingActivity.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.activity; - -import android.app.Activity; -import android.os.Bundle; -import android.support.v4.app.NavUtils; -import android.view.MenuItem; -import net.lacolaco.smileessence.Application; -import net.lacolaco.smileessence.R; - -public class SettingActivity extends Activity { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.layout_setting); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: { - NavUtils.navigateUpFromSameTask(this); - return true; - } - } - return true; - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/activity/SettingActivity.kt b/app/src/main/java/net/lacolaco/smileessence/activity/SettingActivity.kt new file mode 100644 index 00000000..07518480 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/activity/SettingActivity.kt @@ -0,0 +1,49 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.activity + +import android.app.Activity +import android.os.Bundle +import android.support.v4.app.NavUtils +import android.view.MenuItem +import net.lacolaco.smileessence.Application +import net.lacolaco.smileessence.R + +class SettingActivity : Activity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.layout_setting) + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + android.R.id.home -> { + NavUtils.navigateUpFromSameTask(this) + return true + } + } + return true + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/command/Command.java b/app/src/main/java/net/lacolaco/smileessence/command/Command.java deleted file mode 100644 index 0225b886..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/command/Command.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.command; - -import net.lacolaco.smileessence.activity.MainActivity; - -public abstract class Command { - private final MainActivity activity; - - public Command(MainActivity activity) { - this.activity = activity; - } - - protected MainActivity getActivity() { - return activity; - } - - public abstract boolean execute(); - - public abstract String getText(); - -} diff --git a/app/src/main/java/net/lacolaco/smileessence/command/Command.kt b/app/src/main/java/net/lacolaco/smileessence/command/Command.kt new file mode 100644 index 00000000..98183dc7 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/command/Command.kt @@ -0,0 +1,35 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.command + +import net.lacolaco.smileessence.activity.MainActivity + +abstract class Command(protected val activity: MainActivity) { + + abstract fun execute(): Boolean + + abstract val text: String + +} diff --git a/app/src/main/java/net/lacolaco/smileessence/command/CommandAddHashtag.java b/app/src/main/java/net/lacolaco/smileessence/command/CommandAddHashtag.java deleted file mode 100644 index b2de5c21..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/command/CommandAddHashtag.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.command; - -import net.lacolaco.smileessence.activity.MainActivity; - -public class CommandAddHashtag extends Command { - - // ------------------------------ FIELDS ------------------------------ - - private final String hashtag; - - // --------------------------- CONSTRUCTORS --------------------------- - - public CommandAddHashtag(MainActivity activity, String hashtag) { - super(activity); - this.hashtag = hashtag; - } - - // --------------------- GETTER / SETTER METHODS --------------------- - - @Override - public String getText() { - return "#" + hashtag; - } - - // -------------------------- OTHER METHODS -------------------------- - - @Override - public boolean execute() { - getActivity().getWorld().getPostState().beginTransaction().appendText(" #" + hashtag).commit(); - return true; - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/command/CommandAddHashtag.kt b/app/src/main/java/net/lacolaco/smileessence/command/CommandAddHashtag.kt new file mode 100644 index 00000000..5d8077d5 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/command/CommandAddHashtag.kt @@ -0,0 +1,48 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.command + +import net.lacolaco.smileessence.activity.MainActivity + +class CommandAddHashtag +// --------------------------- CONSTRUCTORS --------------------------- + +(activity: MainActivity, + // ------------------------------ FIELDS ------------------------------ + + private val hashtag: String) : Command(activity) { + + // --------------------- GETTER / SETTER METHODS --------------------- + + override val text: String + get() = "#" + hashtag + + // -------------------------- OTHER METHODS -------------------------- + + override fun execute(): Boolean { + activity.world.postState.beginTransaction().appendText(" #" + hashtag).commit() + return true + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/command/CommandOpenURL.java b/app/src/main/java/net/lacolaco/smileessence/command/CommandOpenURL.java deleted file mode 100644 index c62e2601..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/command/CommandOpenURL.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.command; - -import net.lacolaco.smileessence.activity.MainActivity; -import net.lacolaco.smileessence.util.IntentUtils; - -public class CommandOpenURL extends Command { - - // ------------------------------ FIELDS ------------------------------ - - private final String url; - - // --------------------------- CONSTRUCTORS --------------------------- - - public CommandOpenURL(MainActivity activity, String url) { - super(activity); - this.url = url; - } - - // --------------------- GETTER / SETTER METHODS --------------------- - - @Override - public String getText() { - return url; - } - - // -------------------------- OTHER METHODS -------------------------- - - @Override - public boolean execute() { - IntentUtils.openUri(getActivity(), url); - return true; - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/command/CommandOpenURL.kt b/app/src/main/java/net/lacolaco/smileessence/command/CommandOpenURL.kt new file mode 100644 index 00000000..b9150e12 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/command/CommandOpenURL.kt @@ -0,0 +1,46 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.command + +import net.lacolaco.smileessence.activity.MainActivity +import net.lacolaco.smileessence.util.IntentUtils + +class CommandOpenURL +// --------------------------- CONSTRUCTORS --------------------------- + +(activity: MainActivity, + // ------------------------------ FIELDS ------------------------------ + + // --------------------- GETTER / SETTER METHODS --------------------- + + override val text: String) : Command(activity) { + + // -------------------------- OTHER METHODS -------------------------- + + override fun execute(): Boolean { + IntentUtils.openUri(activity, text) + return true + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/command/CommandOpenUserDetail.java b/app/src/main/java/net/lacolaco/smileessence/command/CommandOpenUserDetail.java deleted file mode 100644 index 600e0bc0..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/command/CommandOpenUserDetail.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.command; - -import net.lacolaco.smileessence.R; -import net.lacolaco.smileessence.activity.MainActivity; -import net.lacolaco.smileessence.twitter.task.Users; -import net.lacolaco.smileessence.view.DialogHelper; -import net.lacolaco.smileessence.view.dialog.UserDetailDialogFragment; - -public class CommandOpenUserDetail extends Command { - - // ------------------------------ FIELDS ------------------------------ - - private final String screenName; - - // --------------------------- CONSTRUCTORS --------------------------- - - public CommandOpenUserDetail(MainActivity activity, String screenName) { - super(activity); - this.screenName = screenName; - } - - // --------------------- GETTER / SETTER METHODS --------------------- - - @Override - public String getText() { - return String.format("@%s", screenName); - } - - // -------------------------- OTHER METHODS -------------------------- - - @Override - public boolean execute() { - new Users.GetTask(getActivity().getWorld().getAccount(), screenName) - .onDoneUI(user -> { - UserDetailDialogFragment fragment = new UserDetailDialogFragment(); - fragment.setUserID(user.getId()); - DialogHelper.showDialog(getActivity(), fragment); - }) - .onFail(x -> getActivity().getWorld().notifyError(R.string.notice_error_show_user)) - .execute(); - - return false; - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/command/CommandOpenUserDetail.kt b/app/src/main/java/net/lacolaco/smileessence/command/CommandOpenUserDetail.kt new file mode 100644 index 00000000..89d5d2ef --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/command/CommandOpenUserDetail.kt @@ -0,0 +1,58 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.command + +import net.lacolaco.smileessence.R +import net.lacolaco.smileessence.activity.MainActivity +import net.lacolaco.smileessence.twitter.task.Users +import net.lacolaco.smileessence.view.DialogHelper +import net.lacolaco.smileessence.view.dialog.UserDetailDialogFragment + +class CommandOpenUserDetail +// --------------------------- CONSTRUCTORS --------------------------- + +(activity: MainActivity, + // ------------------------------ FIELDS ------------------------------ + + private val screenName: String) : Command(activity) { + + // --------------------- GETTER / SETTER METHODS --------------------- + + override val text: String + get() = String.format("@%s", screenName) + + // -------------------------- OTHER METHODS -------------------------- + + override fun execute(): Boolean { + Users.GetTask(activity.world.account, screenName) + .onDoneUI { user -> + DialogHelper.showDialog(activity, UserDetailDialogFragment.newInstance(user)) + } + .onFail { x -> activity.world.notifyError(R.string.notice_error_show_user) } + .execute() + + return false + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/compat/Twitter4J.java b/app/src/main/java/net/lacolaco/smileessence/compat/Twitter4J.java new file mode 100644 index 00000000..1d9ab25e --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/compat/Twitter4J.java @@ -0,0 +1,11 @@ +package net.lacolaco.smileessence.compat; + +import twitter4j.StatusListener; +import twitter4j.TwitterStream; + +public class Twitter4J { + // Make it work with Kotlin. Problem exists in v4.0.6 + public static void twitterStreamAddListener(TwitterStream stream, StatusListener listener) { + stream.addListener(listener); + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/data/Account.java b/app/src/main/java/net/lacolaco/smileessence/data/Account.java deleted file mode 100644 index 280f9a09..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/data/Account.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.data; - -import com.github.gfx.android.orma.annotation.Column; -import com.github.gfx.android.orma.annotation.PrimaryKey; -import com.github.gfx.android.orma.annotation.Table; -import net.lacolaco.smileessence.entity.User; -import twitter4j.Twitter; -import twitter4j.TwitterFactory; -import twitter4j.TwitterStream; -import twitter4j.TwitterStreamFactory; -import twitter4j.auth.AccessToken; -import twitter4j.conf.ConfigurationBuilder; - -import java.util.*; - -@Table -public class Account { - private static Map cache; - @PrimaryKey - public long userId; - @Column - public String screenName; - @Column - public String oauthToken; - @Column - public String oauthTokenSecret; - @Column(defaultExpr = "0") - public int themeIndex; - - private User user; - - public Account() { - } - - public static synchronized Account get(long i) { - if (cache == null) { - throw new IllegalStateException("[BUG] Load first"); - } - Account a = cache.get(i); - if (a == null) - throw new IllegalStateException("[BUG] Account with userId == " + i + " not found"); - return a; - } - - public static synchronized List all() { - return new ArrayList<>(cache.values()); - } - - public static synchronized void load() { - cache = new LinkedHashMap<>(); - for (Account item : relation().selector()) - cache.put(item.userId, item); - } - - private static Account_Relation relation() { - OrmaDatabase orma = OrmaHolder.getORMA(); - return orma.relationOfAccount(); - } - - public static synchronized Account register(String token, String tokenSecret, long userId, String screenName) { - Account account = null; - for (Account a : all()) { - if (a.getUserId() == userId) { - account = a; - break; - } - } - if (account == null) - account = new Account(); - account.userId = userId; - account.screenName = screenName; - account.oauthToken = token; - account.oauthTokenSecret = tokenSecret; - account.themeIndex = 0; - - relation().upserter().execute(account); - - cache.put(account.userId, account); - - return account; - } - - public static synchronized Account unregister(long id) { - Account account = cache.remove(id); - if (account != null) { - relation().deleter().userIdEq(id).execute(); - } - return account; - } - - public long getUserId() { - return userId; - } - - public Twitter getTwitter() { - ConfigurationBuilder cb = new ConfigurationBuilder(); - cb.setTweetModeExtended(true); - Twitter twitter = new TwitterFactory(cb.build()).getInstance(); - twitter.setOAuthAccessToken(new AccessToken(oauthToken, oauthTokenSecret)); - return twitter; - } - - public TwitterStream getTwitterStream() { - TwitterStream stream = new TwitterStreamFactory().getInstance(); - stream.setOAuthAccessToken(new AccessToken(oauthToken, oauthTokenSecret)); - return stream; - } - - public User getUser() { - if (user == null) { - user = User.fetch(userId); - if (user == null) { - user = User._makeSkeleton(userId, screenName); - } - user.addObserver(this, (objs) -> { - if (!screenName.equals(user.getScreenName())) { - screenName = user.getScreenName(); - relation().upserter().execute(this); - } - }); - } - - return user; - } -} \ No newline at end of file diff --git a/app/src/main/java/net/lacolaco/smileessence/data/Account.kt b/app/src/main/java/net/lacolaco/smileessence/data/Account.kt new file mode 100644 index 00000000..6dc8262c --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/data/Account.kt @@ -0,0 +1,134 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.data + +import com.github.gfx.android.orma.annotation.Column +import com.github.gfx.android.orma.annotation.PrimaryKey +import com.github.gfx.android.orma.annotation.Table +import net.lacolaco.smileessence.data.Account.Companion.cache +import net.lacolaco.smileessence.entity.User +import twitter4j.Twitter +import twitter4j.TwitterFactory +import twitter4j.TwitterStream +import twitter4j.TwitterStreamFactory +import twitter4j.auth.AccessToken +import twitter4j.conf.ConfigurationBuilder + +import java.util.* + +@Table +class Account { + @PrimaryKey + var userId: Long = 0 + @Column + var screenName: String? = null + @Column + var oauthToken: String? = null + @Column + var oauthTokenSecret: String? = null + @Column(defaultExpr = "0") + var themeIndex: Int = 0 + + val user: User by lazy { + val _user = User.fetch(userId) ?: User._makeSkeleton(userId, screenName!!) + _user.addObserver(this) { objs -> + if (screenName!! != _user.screenName) { + screenName = _user.screenName + relation().upserter().execute(this) + } + } + _user + } + + val twitter: Twitter + get() { + val cb = ConfigurationBuilder() + cb.setTweetModeExtended(true) + val twitter = TwitterFactory(cb.build()).instance + twitter.oAuthAccessToken = AccessToken(oauthToken, oauthTokenSecret) + return twitter + } + + val twitterStream: TwitterStream + get() { + val stream = TwitterStreamFactory().instance + stream.oAuthAccessToken = AccessToken(oauthToken, oauthTokenSecret) + return stream + } + + + companion object { + private var cache: MutableMap? = null + + @Synchronized + operator fun get(i: Long): Account { + if (cache == null) { + throw IllegalStateException("[BUG] Load first") + } + return cache!![i] ?: throw IllegalStateException("[BUG] Account with userId == $i not found") + } + + @Synchronized + fun all(): List { + return ArrayList(cache!!.values) + } + + @Synchronized + fun load() { + cache = LinkedHashMap() + for (item in relation().selector()) + cache!!.put(item.userId, item) + } + + private fun relation(): Account_Relation { + return OrmaHolder.orma.relationOfAccount() + } + + @Synchronized + fun register(token: String, tokenSecret: String, userId: Long, screenName: String): Account { + val account = all().find { a -> a.userId == userId } ?: Account() + account.userId = userId + account.screenName = screenName + account.oauthToken = token + account.oauthTokenSecret = tokenSecret + account.themeIndex = 0 + + relation().upserter().execute(account) + + cache!!.put(account.userId, account) + + return account + } + + @Synchronized + fun unregister(id: Long): Account? { + val account = cache!!.remove(id) + if (account != null) { + relation().deleter().userIdEq(id).execute() + } + return account + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/lacolaco/smileessence/data/ExtractionWord.java b/app/src/main/java/net/lacolaco/smileessence/data/ExtractionWord.java deleted file mode 100644 index 334ab5e7..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/data/ExtractionWord.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.data; - -import com.github.gfx.android.orma.annotation.PrimaryKey; -import com.github.gfx.android.orma.annotation.Table; - -import java.util.*; -import java.util.regex.Pattern; - -@Table -public class ExtractionWord { - private static Set cache; - @PrimaryKey - String patternString; - private Pattern pattern; - - public ExtractionWord() { - } - - private ExtractionWord(String patternString) { - this.patternString = patternString; - } - - public static synchronized Collection cached() { - return cache; - } - - public static synchronized void load() { - OrmaDatabase orma = OrmaHolder.getORMA(); - cache = new HashSet<>(orma.selectFromExtractionWord().toList()); - } - - private static ExtractionWord_Relation relation() { - return OrmaHolder.getORMA().relationOfExtractionWord(); - } - - public static synchronized ExtractionWord add(String patternString) { - ExtractionWord extractionWord = new ExtractionWord(patternString); - relation().upserter().execute(extractionWord); - cache.add(extractionWord); - return extractionWord; - } - - public Pattern getPattern() { - if (pattern == null) - pattern = Pattern.compile(patternString); - return pattern; - } - - public String getPatternString() { - return patternString; - } - - public void remove() { - relation().deleter().patternStringEq(patternString).execute(); - cache.remove(this); - } -} \ No newline at end of file diff --git a/app/src/main/java/net/lacolaco/smileessence/data/ExtractionWord.kt b/app/src/main/java/net/lacolaco/smileessence/data/ExtractionWord.kt new file mode 100644 index 00000000..6fd1be36 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/data/ExtractionWord.kt @@ -0,0 +1,54 @@ +package net.lacolaco.smileessence.data + +import com.github.gfx.android.orma.annotation.PrimaryKey +import com.github.gfx.android.orma.annotation.Table + +import java.util.* +import java.util.regex.Pattern + +@Table +class ExtractionWord { + @PrimaryKey + lateinit var patternString: String + + val pattern: Pattern by lazy { + Pattern.compile(patternString) + } + + constructor() + + private constructor(patternString: String) { + this.patternString = patternString + } + + fun remove() { + relation().deleter().patternStringEq(patternString).execute() + cache!!.remove(this) + } + + companion object { + private var cache: MutableSet? = null + + @Synchronized + fun cached(): Collection { + return cache ?: throw IllegalStateException("extraction pattern not loaded") + } + + @Synchronized + fun load() { + cache = HashSet(OrmaHolder.orma.selectFromExtractionWord().toList()) + } + + private fun relation(): ExtractionWord_Relation { + return OrmaHolder.orma.relationOfExtractionWord() + } + + @Synchronized + fun add(patternString: String): ExtractionWord { + val extractionWord = ExtractionWord(patternString) + relation().upserter().execute(extractionWord) + cache!!.add(extractionWord) + return extractionWord + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/lacolaco/smileessence/data/ImageCache.java b/app/src/main/java/net/lacolaco/smileessence/data/ImageCache.java deleted file mode 100644 index daa2a443..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/data/ImageCache.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.data; - -import android.graphics.Bitmap; -import android.util.LruCache; -import com.android.volley.Cache; -import com.android.volley.RequestQueue; -import com.android.volley.toolbox.*; -import net.lacolaco.smileessence.Application; - -public class ImageCache { - private static ImageCache instance = new ImageCache(); - private ImageLoader imageLoader; - - private ImageCache() { - int cacheSizeInBytes = 64 * 1024 * 1024; // 64MB - Cache diskCache = new DiskBasedCache(Application.getInstance().getCacheDir(), cacheSizeInBytes); - RequestQueue requestQueue = new RequestQueue(diskCache, new BasicNetwork(new HurlStack())); - imageLoader = new ImageLoader(requestQueue, new ImageLruCache()); - requestQueue.start(); - } - - public static ImageLoader getImageLoader() { return instance.imageLoader; } - - private static class ImageLruCache implements ImageLoader.ImageCache { - private LruCache cache; - - private ImageLruCache() { - cache = new LruCache<>(4 * 1024 * 1024); // 4MB - } - - @Override - public Bitmap getBitmap(String url) { - return cache.get(url); - } - - @Override - public void putBitmap(String url, Bitmap bitmap) { - cache.put(url, bitmap); - } - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/data/ImageCache.kt b/app/src/main/java/net/lacolaco/smileessence/data/ImageCache.kt new file mode 100644 index 00000000..d7b4eeac --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/data/ImageCache.kt @@ -0,0 +1,64 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.data + +import android.graphics.Bitmap +import android.util.LruCache +import com.android.volley.Cache +import com.android.volley.RequestQueue +import com.android.volley.toolbox.* +import net.lacolaco.smileessence.Application + +class ImageCache private constructor() { + private val imageLoader: ImageLoader + + init { + val cacheSizeInBytes = 64 * 1024 * 1024 // 64MB + val diskCache = DiskBasedCache(Application.getInstance().cacheDir, cacheSizeInBytes) + val requestQueue = RequestQueue(diskCache, BasicNetwork(HurlStack())) + imageLoader = ImageLoader(requestQueue, ImageLruCache()) + requestQueue.start() + } + + private class ImageLruCache : ImageLoader.ImageCache { + private val cache: LruCache = LruCache(4 * 1024 * 1024) // 4MB + + override fun getBitmap(url: String): Bitmap? { + return cache.get(url) + } + + override fun putBitmap(url: String, bitmap: Bitmap) { + cache.put(url, bitmap) + } + } + + companion object { + private val instance = ImageCache() + + fun getImageLoader(): ImageLoader { + return instance.imageLoader + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/data/OrmaHolder.java b/app/src/main/java/net/lacolaco/smileessence/data/OrmaHolder.java deleted file mode 100644 index 5fd41c0c..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/data/OrmaHolder.java +++ /dev/null @@ -1,19 +0,0 @@ -package net.lacolaco.smileessence.data; - -import android.content.Context; -import com.github.gfx.android.orma.AccessThreadConstraint; - -public class OrmaHolder { - private static OrmaDatabase ORMA; - - public static void initialize(Context context) { - ORMA = OrmaDatabase - .builder(context) - .writeOnMainThread(AccessThreadConstraint.WARNING) - .build(); - } - - public static OrmaDatabase getORMA() { - return ORMA; - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/data/OrmaHolder.kt b/app/src/main/java/net/lacolaco/smileessence/data/OrmaHolder.kt new file mode 100644 index 00000000..f05f4def --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/data/OrmaHolder.kt @@ -0,0 +1,16 @@ +package net.lacolaco.smileessence.data + +import android.content.Context +import com.github.gfx.android.orma.AccessThreadConstraint + +object OrmaHolder { + lateinit var orma: OrmaDatabase + private set + + fun initialize(context: Context) { + orma = OrmaDatabase + .builder(context) + .writeOnMainThread(AccessThreadConstraint.WARNING) + .build() + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/data/PostState.java b/app/src/main/java/net/lacolaco/smileessence/data/PostState.java deleted file mode 100644 index 4bbd83a4..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/data/PostState.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.data; - -import net.lacolaco.smileessence.activity.MainActivity; -import net.lacolaco.smileessence.entity.Tweet; -import net.lacolaco.smileessence.view.DialogHelper; -import twitter4j.StatusUpdate; - -public class PostState { - private String text = ""; - private Tweet inReplyTo; - private String mediaFilePath = ""; - private boolean directMessage = false; - private OnPostStateChangeListener listener; - private int selectionStart, selectionEnd; - - public Tweet getInReplyTo() { - return inReplyTo; - } - - public String getMediaFilePath() { - return mediaFilePath; - } - - public int getSelectionEnd() { - if (selectionEnd < 0) { - return text.length(); - } - return selectionEnd; - } - - public int getSelectionStart() { - if (selectionStart < 0) { - return text.length(); - } - return selectionStart; - } - - public String getText() { - return text; - } - - public PostState setListener(OnPostStateChangeListener listener) { - this.listener = listener; - return this; - } - - public PostStateTransaction beginTransaction() { - return new PostStateTransaction(this); - } - - public void removeListener() { - this.listener = null; - } - - /** - * Convert to StatusUpdate for tweet. - * - * @return StatusUpdate - */ - public StatusUpdate toStatusUpdate() { - StatusUpdate su = new StatusUpdate(getText()); - if (getInReplyTo() != null) { - su.setInReplyToStatusId(getInReplyTo().getId()); - } - return su; - } - - private PostState copy(PostState another) { - this.text = another.text; - this.inReplyTo = another.getInReplyTo(); - this.mediaFilePath = another.mediaFilePath; - this.directMessage = another.directMessage; - this.selectionStart = another.selectionStart; - this.selectionEnd = another.selectionEnd; - this.listener = another.listener; - return this; - } - - private void postStateChange() { - if (listener != null) { - listener.onPostStateChange(this); - } - } - - // -------------------------- INNER CLASSES -------------------------- - - public interface OnPostStateChangeListener { - - void onPostStateChange(PostState postState); - } - - public static class PostStateTransaction { - private PostState origState, state; - - private PostStateTransaction(PostState state) { - this.origState = state; - this.state = new PostState().copy(state); - } - - public PostStateTransaction setText(String text) { - state.text = text; - return this; - } - - public PostStateTransaction appendText(String text) { - state.text = state.text + text; - return this; - } - - public PostStateTransaction insertText(int index, String text) { - StringBuilder builder = new StringBuilder(state.text); - builder.insert(index, text); - state.text = builder.toString(); - return this; - } - - public PostStateTransaction setInReplyTo(Tweet inReplyTo) { - state.inReplyTo = inReplyTo; - return this; - } - - public PostStateTransaction setMediaFilePath(String mediaFilePath) { - state.mediaFilePath = mediaFilePath; - return this; - } - - public PostStateTransaction setCursor(int cursor) { - state.selectionStart = state.selectionEnd = cursor; - return this; - } - - public PostStateTransaction setSelection(int start, int end) { - state.selectionStart = start; - state.selectionEnd = end; - return this; - } - - public PostStateTransaction clear() { - state.text = ""; - state.selectionStart = state.selectionEnd = 0; - state.inReplyTo = null; - return this; - } - - public void commit() { - origState.copy(state).postStateChange(); - } - - public void commitWithOpen(MainActivity activity) { - DialogHelper.closeAll(activity); - origState.copy(state).postStateChange(); - activity.openPostPage(); - } - - public PostStateTransaction moveCursor(int length) { - int cursor = state.selectionEnd + length; - return setCursor(cursor); - } - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/data/PostState.kt b/app/src/main/java/net/lacolaco/smileessence/data/PostState.kt new file mode 100644 index 00000000..4bc07443 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/data/PostState.kt @@ -0,0 +1,167 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.data + +import net.lacolaco.smileessence.activity.MainActivity +import net.lacolaco.smileessence.entity.Tweet +import net.lacolaco.smileessence.view.DialogHelper +import twitter4j.StatusUpdate + +class PostState { + var text = "" + private set + var inReplyTo: Tweet? = null + private set + var mediaFilePath = "" + private set + private var listener: OnPostStateChangeListener? = null + var selectionStart: Int = 0 + get() { + return if (field < 0) { + text.length + } else field + } + var selectionEnd: Int = 0 + get() { + return if (field < 0) { + text.length + } else field + } + + fun setListener(listener: OnPostStateChangeListener): PostState { + this.listener = listener + return this + } + + fun beginTransaction(): PostStateTransaction { + return PostStateTransaction(this) + } + + fun removeListener() { + this.listener = null + } + + /** + * Convert to StatusUpdate for tweet. + * + * @return StatusUpdate + */ + fun toStatusUpdate(): StatusUpdate { + val su = StatusUpdate(text) + if (inReplyTo != null) { + su.inReplyToStatusId = inReplyTo!!.id + } + return su + } + + private fun copy(another: PostState): PostState { + this.text = another.text + this.inReplyTo = another.inReplyTo + this.mediaFilePath = another.mediaFilePath + this.selectionStart = another.selectionStart + this.selectionEnd = another.selectionEnd + this.listener = another.listener + return this + } + + private fun postStateChange() { + if (listener != null) { + listener!!.onPostStateChange(this) + } + } + + // -------------------------- INNER CLASSES -------------------------- + + interface OnPostStateChangeListener { + + fun onPostStateChange(postState: PostState) + } + + class PostStateTransaction constructor(private val origState: PostState) { + private val state: PostState = PostState().copy(origState) + + fun setText(text: String): PostStateTransaction { + state.text = text + return this + } + + fun appendText(text: String): PostStateTransaction { + state.text = state.text + text + return this + } + + fun insertText(index: Int, text: String): PostStateTransaction { + val builder = StringBuilder(state.text) + builder.insert(index, text) + state.text = builder.toString() + return this + } + + fun setInReplyTo(inReplyTo: Tweet?): PostStateTransaction { + state.inReplyTo = inReplyTo + return this + } + + fun setMediaFilePath(mediaFilePath: String): PostStateTransaction { + state.mediaFilePath = mediaFilePath + return this + } + + fun setCursor(cursor: Int): PostStateTransaction { + state.selectionEnd = cursor + state.selectionStart = state.selectionEnd + return this + } + + fun setSelection(start: Int, end: Int): PostStateTransaction { + state.selectionStart = start + state.selectionEnd = end + return this + } + + fun clear(): PostStateTransaction { + state.text = "" + state.selectionEnd = 0 + state.selectionStart = state.selectionEnd + state.inReplyTo = null + return this + } + + fun commit() { + origState.copy(state).postStateChange() + } + + fun commitWithOpen(activity: MainActivity) { + DialogHelper.closeAll(activity) + origState.copy(state).postStateChange() + activity.openPostPage() + } + + fun moveCursor(length: Int): PostStateTransaction { + val cursor = state.selectionEnd + length + return setCursor(cursor) + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/entity/DirectMessage.java b/app/src/main/java/net/lacolaco/smileessence/entity/DirectMessage.java deleted file mode 100644 index f2862151..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/entity/DirectMessage.java +++ /dev/null @@ -1,71 +0,0 @@ -package net.lacolaco.smileessence.entity; - -import net.lacolaco.smileessence.util.ListUtils; - -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class DirectMessage extends EntitySupport implements IdObject { - private static Map storage = new HashMap<>(); - private long id; - private User sender; - private User recipient; - private String text; - private Date createdAt; - - private DirectMessage(twitter4j.DirectMessage st) { - update(st); - } - - public synchronized static DirectMessage fetch(long statusId) { - return storage.get(statusId); - } - - public synchronized static DirectMessage fromTwitter(twitter4j.DirectMessage st) { - DirectMessage t = fetch(st.getId()); - if (t == null) { - t = new DirectMessage(st); - storage.put(st.getId(), t); - } else { - t.update(st); - } - return t; - } - - public synchronized static List fromTwitter(List sts) { - return ListUtils.map(sts, DirectMessage::fromTwitter); - } - - private void update(twitter4j.DirectMessage message) { - id = message.getId(); - sender = User.fromTwitter(message.getSender()); - recipient = User.fromTwitter(message.getRecipient()); - text = extractText(message, false); - createdAt = message.getCreatedAt(); - - updateEntities(message); - } - - @Override - public long getId() { - return id; - } - - public User getSender() { - return sender; - } - - public User getRecipient() { - return recipient; - } - - public String getText() { - return text; - } - - public Date getCreatedAt() { - return createdAt; - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/entity/DirectMessage.kt b/app/src/main/java/net/lacolaco/smileessence/entity/DirectMessage.kt new file mode 100644 index 00000000..e89868f8 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/entity/DirectMessage.kt @@ -0,0 +1,44 @@ +package net.lacolaco.smileessence.entity + +import java.util.Date +import java.util.HashMap + +class DirectMessage private constructor(message: twitter4j.DirectMessage) : EntitySupport(), IdObject { + override val id: Long = message.id + val sender: User = User.fromTwitter(message.sender) + val recipient: User = User.fromTwitter(message.recipient) + val text: String = extractText(message, false) + val createdAt: Date = message.createdAt + + init { + updateEntities(message) + } + + companion object { + private val storage = HashMap() + + @Synchronized + fun fetch(statusId: Long): DirectMessage? { + return storage[statusId] + } + + @Synchronized + fun fromTwitter(st: twitter4j.DirectMessage): DirectMessage { + var t: DirectMessage? = fetch(st.id) + if (t == null) { + t = DirectMessage(st) + storage.put(st.id, t) + } else { + // Update local cache + User.fromTwitter(st.sender) + User.fromTwitter(st.recipient) + } + return t + } + + @Synchronized + fun fromTwitter(sts: Iterable): List { + return sts.map { fromTwitter(it) } + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/entity/EntitySupport.java b/app/src/main/java/net/lacolaco/smileessence/entity/EntitySupport.java deleted file mode 100644 index 9629bea2..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/entity/EntitySupport.java +++ /dev/null @@ -1,121 +0,0 @@ -package net.lacolaco.smileessence.entity; - -import net.lacolaco.smileessence.util.UIObservable; -import twitter4j.*; - -import java.util.*; - -public abstract class EntitySupport extends UIObservable { - private List mentions; - private List hashtags; - private List mediaUrls; - private List urlsExpanded; - private List symbols; - - protected void updateEntities(twitter4j.EntitySupport status) { - mentions = extractMentions(status.getUserMentionEntities()); - hashtags = extractHashtags(status.getHashtagEntities()); - mediaUrls = extractMediaUrls(status.getMediaEntities()); - urlsExpanded = extractExpandedUrls(status.getURLEntities()); - symbols = extractSymbols(status.getSymbolEntities()); - } - - public List getMentions() { - return mentions; - } - - public List getHashtags() { - return hashtags; - } - - public List getMediaUrls() { - return mediaUrls; - } - - public List getUrlsExpanded() { - return urlsExpanded; - } - - public List getSymbols() { - return symbols; - } - - private List extractMentions(UserMentionEntity[] entities) { - List names = new ArrayList<>(); - if (entities != null) { - for (UserMentionEntity entity : entities) { - names.add(entity.getScreenName()); - } - } - return names; - } - - private List extractSymbols(SymbolEntity[] entities) { - List names = new ArrayList<>(); - if (entities != null) { - for (SymbolEntity entity : entities) { - names.add(entity.getText()); - } - } - return names; - } - - private List extractExpandedUrls(URLEntity[] entities) { - List names = new ArrayList<>(); - if (entities != null) { - for (URLEntity entity : entities) { - names.add(entity.getExpandedURL()); - } - } - return names; - } - - private List extractMediaUrls(MediaEntity[] entities) { - List names = new ArrayList<>(); - if (entities != null) { - for (MediaEntity entity : entities) { - if ("photo".equals(entity.getType())) { - names.add(entity.getMediaURLHttps()); - } else { - names.add(entity.getExpandedURL()); - } - } - } - return names; - } - - private List extractHashtags(HashtagEntity[] entities) { - List names = new ArrayList<>(); - if (entities != null) { - for (HashtagEntity entity : entities) { - names.add(entity.getText()); - } - } - return names; - } - - protected String extractText(twitter4j.Status status, boolean expand) { - return extractText(status, status.getText(), expand); - } - - protected String extractText(twitter4j.DirectMessage status, boolean expand) { - return extractText(status, status.getText(), expand); - } - - private String extractText(twitter4j.EntitySupport status, String text, boolean expand) { - SortedSet set = new TreeSet<>((a, b) -> a.getStart() - b.getStart()); - if (status.getURLEntities() != null) { - Collections.addAll(set, status.getURLEntities()); - } - if (status.getMediaEntities() != null) { - Collections.addAll(set, status.getMediaEntities()); - } - - for (URLEntity entity : set) { - String newString = expand ? entity.getExpandedURL() : entity.getDisplayURL(); - text = text.replaceFirst(entity.getText(), newString); - } - - return text; - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/entity/EntitySupport.kt b/app/src/main/java/net/lacolaco/smileessence/entity/EntitySupport.kt new file mode 100644 index 00000000..c1b3e4a3 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/entity/EntitySupport.kt @@ -0,0 +1,106 @@ +package net.lacolaco.smileessence.entity + +import net.lacolaco.smileessence.util.UIObservable +import twitter4j.* + +import java.util.* + +abstract class EntitySupport : UIObservable() { + open lateinit var mentions: List + protected set + open lateinit var hashtags: List + protected set + open lateinit var mediaUrls: List + protected set + open lateinit var urlsExpanded: List + protected set + open lateinit var symbols: List + protected set + + protected fun updateEntities(status: twitter4j.EntitySupport) { + mentions = extractMentions(status.userMentionEntities) + hashtags = extractHashtags(status.hashtagEntities) + mediaUrls = extractMediaUrls(status.mediaEntities) + urlsExpanded = extractExpandedUrls(status.urlEntities) + symbols = extractSymbols(status.symbolEntities) + } + + private fun extractMentions(entities: Array?): List { + val names = ArrayList() + if (entities != null) { + for (entity in entities) { + names.add(entity.screenName) + } + } + return names + } + + private fun extractSymbols(entities: Array?): List { + val names = ArrayList() + if (entities != null) { + for (entity in entities) { + names.add(entity.text) + } + } + return names + } + + private fun extractExpandedUrls(entities: Array?): List { + val names = ArrayList() + if (entities != null) { + for (entity in entities) { + names.add(entity.expandedURL) + } + } + return names + } + + private fun extractMediaUrls(entities: Array?): List { + val names = ArrayList() + if (entities != null) { + for (entity in entities) { + if ("photo" == entity.type) { + names.add(entity.mediaURLHttps) + } else { + names.add(entity.expandedURL) + } + } + } + return names + } + + private fun extractHashtags(entities: Array?): List { + val names = ArrayList() + if (entities != null) { + for (entity in entities) { + names.add(entity.text) + } + } + return names + } + + protected fun extractText(status: twitter4j.Status, expand: Boolean): String { + return extractText(status, status.text, expand) + } + + protected fun extractText(status: twitter4j.DirectMessage, expand: Boolean): String { + return extractText(status, status.text, expand) + } + + private fun extractText(status: twitter4j.EntitySupport, text: String, expand: Boolean): String { + val set = TreeSet { a, b -> a.start - b.start } + if (status.urlEntities != null) { + Collections.addAll(set, *status.urlEntities) + } + if (status.mediaEntities != null) { + Collections.addAll(set, *status.mediaEntities) + } + + var t = text + for (entity in set) { + val newString = if (expand) entity.expandedURL else entity.displayURL + t = t.replaceFirst(entity.text.toRegex(), newString) + } + return t + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/entity/Event.java b/app/src/main/java/net/lacolaco/smileessence/entity/Event.java deleted file mode 100644 index e2002cb9..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/entity/Event.java +++ /dev/null @@ -1,62 +0,0 @@ -package net.lacolaco.smileessence.entity; - -import java.util.Date; - -public class Event { - private final Date createdAt; - private final EnumEvent event; - private final User source; - private final Tweet targetObject; - - public Event(EnumEvent e, User s) { - this(e, s, null); - } - - public Event(EnumEvent e, User s, Tweet t) { - event = e; - createdAt = new Date(); - source = s; - targetObject = t; - } - - public Date getCreatedAt() { - return createdAt; - } - - public EnumEvent getEvent() { - return event; - } - - public User getSource() { - return source; - } - - public Tweet getTargetObject() { - return targetObject; - } - - public String getFormattedString() { - return String.format(event.getFormat(), source.getScreenName()); - } - - public enum EnumEvent { - FAVORITED("Favorited by %s"), - UNFAVORITED("Unfavorited by %s"), - RETWEETED("Retweeted by %s"), - MENTIONED("Replied by %s"), - FOLLOWED("Followed by %s"), - BLOCKED("Blocked by %s"), - UNBLOCKED("Unblocked by %s"), - RECEIVE_MESSAGE("Received a direct message from %s"); - - private final String format; - - EnumEvent(String f) { - format = f; - } - - public String getFormat() { - return format; - } - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/entity/Event.kt b/app/src/main/java/net/lacolaco/smileessence/entity/Event.kt new file mode 100644 index 00000000..d7d7a9cd --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/entity/Event.kt @@ -0,0 +1,20 @@ +package net.lacolaco.smileessence.entity + +import java.util.Date + +class Event constructor(val event: EnumEvent, val source: User, val targetObject: Tweet? = null) { + val createdAt: Date = Date() + val formattedString: String + get() = String.format(event.format, source.screenName) + + enum class EnumEvent(val format: String) { + FAVORITED("Favorited by %s"), + UNFAVORITED("Unfavorited by %s"), + RETWEETED("Retweeted by %s"), + MENTIONED("Replied by %s"), + FOLLOWED("Followed by %s"), + BLOCKED("Blocked by %s"), + UNBLOCKED("Unblocked by %s"), + RECEIVE_MESSAGE("Received a direct message from %s") + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/entity/IdObject.java b/app/src/main/java/net/lacolaco/smileessence/entity/IdObject.java deleted file mode 100644 index 444a627b..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/entity/IdObject.java +++ /dev/null @@ -1,5 +0,0 @@ -package net.lacolaco.smileessence.entity; - -public interface IdObject { - long getId(); -} diff --git a/app/src/main/java/net/lacolaco/smileessence/entity/IdObject.kt b/app/src/main/java/net/lacolaco/smileessence/entity/IdObject.kt new file mode 100644 index 00000000..eb08d55f --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/entity/IdObject.kt @@ -0,0 +1,5 @@ +package net.lacolaco.smileessence.entity + +interface IdObject { + val id: Long +} diff --git a/app/src/main/java/net/lacolaco/smileessence/entity/RBinding.java b/app/src/main/java/net/lacolaco/smileessence/entity/RBinding.java deleted file mode 100644 index 5ade81b2..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/entity/RBinding.java +++ /dev/null @@ -1,12 +0,0 @@ -package net.lacolaco.smileessence.entity; - -public enum RBinding { - // Tweet - REACTION_COUNT, - FAVORITERS, - RETWEETERS, - - // User - BASIC, - DETAIL,; -} diff --git a/app/src/main/java/net/lacolaco/smileessence/entity/RBinding.kt b/app/src/main/java/net/lacolaco/smileessence/entity/RBinding.kt new file mode 100644 index 00000000..1a25cdd5 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/entity/RBinding.kt @@ -0,0 +1,12 @@ +package net.lacolaco.smileessence.entity + +enum class RBinding { + // Tweet + REACTION_COUNT, + FAVORITERS, + RETWEETERS, + + // User + BASIC, + DETAIL +} diff --git a/app/src/main/java/net/lacolaco/smileessence/entity/SavedSearch.java b/app/src/main/java/net/lacolaco/smileessence/entity/SavedSearch.java deleted file mode 100644 index 8fcd0acd..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/entity/SavedSearch.java +++ /dev/null @@ -1,24 +0,0 @@ -package net.lacolaco.smileessence.entity; - -public class SavedSearch implements IdObject { - private long id; - private String query; - - private SavedSearch(long id, String query) { - this.id = id; - this.query = query; - } - - public synchronized static SavedSearch fromTwitter(twitter4j.SavedSearch obj) { - return new SavedSearch(obj.getId(), obj.getQuery()); - } - - @Override - public long getId() { - return id; - } - - public String getQuery() { - return query; - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/entity/SavedSearch.kt b/app/src/main/java/net/lacolaco/smileessence/entity/SavedSearch.kt new file mode 100644 index 00000000..318a2184 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/entity/SavedSearch.kt @@ -0,0 +1,10 @@ +package net.lacolaco.smileessence.entity + +class SavedSearch private constructor(override val id: Long, val query: String) : IdObject { + companion object { + @Synchronized + fun fromTwitter(obj: twitter4j.SavedSearch): SavedSearch { + return SavedSearch(obj.id, obj.query) + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/entity/Tweet.java b/app/src/main/java/net/lacolaco/smileessence/entity/Tweet.java deleted file mode 100644 index c79c58ef..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/entity/Tweet.java +++ /dev/null @@ -1,281 +0,0 @@ -package net.lacolaco.smileessence.entity; - -import android.net.Uri; -import net.lacolaco.smileessence.data.Account; -import net.lacolaco.smileessence.twitter.task.Tweets; -import net.lacolaco.smileessence.util.BackgroundTask; -import net.lacolaco.smileessence.util.ListUtils; -import twitter4j.Status; - -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; - -public class Tweet extends EntitySupport implements IdObject { - private static Map storage = new HashMap<>(); - private final long id; - private User user; - private String text; - private Date createdAt; - private String source; - private boolean isRetweet; - private Tweet retweetedTweet; - private long inReplyToStatusId; - private int favoriteCount; - private int retweetCount; - private Set favoriters; - private Map retweets; - - private Tweet(long id) { - this.id = id; - } - - public synchronized static Tweet fetch(long statusId) { - return storage.get(statusId); - } - - public synchronized static BackgroundTask fetchTask(long statusId, Account account) { - Tweet tweet = fetch(statusId); - if (tweet != null) { - return new BackgroundTask() { - @Override - protected Tweet doInBackground() throws Exception { - return tweet; - } - }; - } else { - return new Tweets.GetTask(account, statusId); - } - } - - public synchronized static Tweet fromTwitter(final twitter4j.Status st, long myUserId) { - Tweet t = fetch(st.getId()); - if (t == null) { - t = new Tweet(st.getId()); - storage.put(st.getId(), t); - } - - t.update(st, myUserId); - return t; - } - - public synchronized static List fromTwitter(List sts, long myUserId) { - return ListUtils.map(sts, st -> fromTwitter(st, myUserId)); - } - - @Override - protected void finalize() throws Throwable { - try { - super.finalize(); - } finally { - Tweet original = getRetweetedTweet(); - if (original != null) { - original.removeRetweet(getId()); - } - } - } - - private void update(twitter4j.Status status, long myUserId) { - if (id != status.getId()) - throw new IllegalStateException("Invalid update"); - user = User.fromTwitter(status.getUser()); - createdAt = status.getCreatedAt(); - source = status.getSource(); - isRetweet = status.isRetweet(); - - if (!isRetweet) { - text = extractText(status, false); - inReplyToStatusId = status.getInReplyToStatusId(); - updateEntities(status); - if (favoriters == null) favoriters = Collections.newSetFromMap(new ConcurrentHashMap<>()); - if (retweets == null) retweets = new ConcurrentHashMap<>(); - - if (favoriteCount != status.getFavoriteCount() || retweetCount != status.getRetweetCount()) { - favoriteCount = status.getFavoriteCount(); - retweetCount = status.getRetweetCount(); - - notifyChange(RBinding.REACTION_COUNT); - } - - if (status.isFavorited()) { - addFavoriter(myUserId); - } else { - removeFavoriter(myUserId); - } - if (status.getCurrentUserRetweetId() > 0) { - addRetweet(myUserId, status.getCurrentUserRetweetId()); - } - } else { - retweetedTweet = Tweet.fromTwitter(status.getRetweetedStatus(), myUserId); - retweetedTweet.addRetweet(this); - if (status.isFavorited()) { - retweetedTweet.addFavoriter(myUserId); - } - if (status.getCurrentUserRetweetId() > 0) { - retweetedTweet.addRetweet(myUserId, status.getCurrentUserRetweetId()); - } - } - } - - public String getTwitterUrl() { - return String.format("https://twitter.com/%s/status/%s", getUser().getScreenName(), id); - } - - @Override - public long getId() { - return id; - } - - public User getUser() { - return user; - } - - public String getText() { - return getOriginalTweet().text; - } - - public Date getCreatedAt() { - return createdAt; - } - - public String getSource() { - return source; - } - - public boolean isRetweet() { - return isRetweet; - } - - public Tweet getRetweetedTweet() { - return retweetedTweet; - } - - public Tweet getOriginalTweet() { - if (isRetweet()) { - return getRetweetedTweet(); - } else { - return this; - } - } - - public int getFavoriteCount() { - return getOriginalTweet().favoriteCount; - } - - public int getRetweetCount() { - return getOriginalTweet().retweetCount; - } - - public long getInReplyToStatusId() { - return getOriginalTweet().inReplyToStatusId; - } - - public boolean isFavoritedBy(long id) { - return getOriginalTweet().favoriters.contains(id); - } - - public Set getFavoriters() { - return getOriginalTweet().favoriters; - } - - public boolean addFavoriter(long id) { - boolean changed = getOriginalTweet().favoriters.add(id); - if (changed) notifyChange(RBinding.FAVORITERS); - return changed; - } - - public boolean removeFavoriter(long id) { - boolean changed = getOriginalTweet().favoriters.remove(id); - if (changed) notifyChange(RBinding.FAVORITERS); - return changed; - } - - public boolean isRetweetedBy(long id) { - return getOriginalTweet().retweets.get(id) != null; - } - - public long getRetweetIdBy(long id) { - return getOriginalTweet().retweets.get(id); - } - - public Map getRetweets() { - return getOriginalTweet().retweets; - } - - public boolean addRetweet(Tweet retweet) { - return addRetweet(retweet.getUser().getId(), retweet.getId()); - } - - public boolean addRetweet(long uid, long sid) { - Long result = getOriginalTweet().retweets.put(uid, sid); - boolean changed = result == null || result != sid; - if (changed) notifyChange(RBinding.RETWEETERS); - return changed; - } - - private boolean removeRetweet(long sid) { - boolean changed = getOriginalTweet().retweets.values().remove(sid); - if (changed) notifyChange(RBinding.RETWEETERS); - return changed; - } - - // helper methods:: - public List getEmbeddedStatusIDs() { - ArrayList list = new ArrayList<>(); - for (String url : getUrlsExpanded()) { - Uri uri = Uri.parse(url); - if ("twitter.com".equals(uri.getHost())) { - String[] arr = uri.toString().split("/"); - if (arr.length > 2 && "status".equals(arr[arr.length - 2])) { - list.add(Long.parseLong(arr[arr.length - 1].split("\\?")[0])); - } - } - } - return list; - } - - // override EntitySupport - @Override - public List getMentions() { - if (isRetweet) { - return getOriginalTweet().getMentions(); - } else { - return super.getMentions(); - } - } - - @Override - public List getHashtags() { - if (isRetweet) { - return getOriginalTweet().getHashtags(); - } else { - return super.getHashtags(); - } - } - - @Override - public List getMediaUrls() { - if (isRetweet) { - return getOriginalTweet().getMediaUrls(); - } else { - return super.getMediaUrls(); - } - } - - @Override - public List getUrlsExpanded() { - if (isRetweet) { - return getOriginalTweet().getUrlsExpanded(); - } else { - return super.getUrlsExpanded(); - } - } - - @Override - public List getSymbols() { - if (isRetweet) { - return getOriginalTweet().getSymbols(); - } else { - return super.getSymbols(); - } - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/entity/Tweet.kt b/app/src/main/java/net/lacolaco/smileessence/entity/Tweet.kt new file mode 100644 index 00000000..437e69c7 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/entity/Tweet.kt @@ -0,0 +1,197 @@ +package net.lacolaco.smileessence.entity + +import android.net.Uri +import net.lacolaco.smileessence.data.Account +import net.lacolaco.smileessence.twitter.task.Tweets +import net.lacolaco.smileessence.util.BackgroundTask +import twitter4j.Status + +import java.util.* +import java.util.concurrent.ConcurrentHashMap + +class Tweet private constructor(st: twitter4j.Status, myUserId: Long) : EntitySupport(), IdObject { + override val id: Long = st.id + val user: User = User.fromTwitter(st.user) + val text: String = extractText(st, false) + get() { + return if (isRetweet) originalTweet.text else field + } + val createdAt: Date = st.createdAt + val source: String = st.source + val isRetweet: Boolean = st.isRetweet + val retweetedTweet: Tweet? = if (st.isRetweet) Tweet.fromTwitter(st.retweetedStatus, myUserId) else null + val originalTweet: Tweet + get() = retweetedTweet ?: this + val inReplyToStatusId: Long = st.inReplyToStatusId + get() = if (isRetweet) originalTweet.inReplyToStatusId else field + var favoriteCount: Int = st.favoriteCount + get() = if (isRetweet) originalTweet.originalTweet.favoriteCount else field + private set + var retweetCount: Int = st.retweetCount + get() = if (isRetweet) originalTweet.originalTweet.retweetCount else field + private set + private val favoriters: MutableSet = Collections.newSetFromMap(ConcurrentHashMap()) + private val retweets: MutableMap = ConcurrentHashMap() + + protected fun finalize() { + retweetedTweet?.retweets?.remove(id) + } + + init { + updateEntities(st) + update(st, myUserId) + } + + private fun update(status: twitter4j.Status, myUserId: Long) { + User.fromTwitter(status.user) + if (retweetedTweet != null) { + Tweet.fromTwitter(status.retweetedStatus, myUserId) + if (status.isFavorited) { + retweetedTweet.favoriters.add(myUserId) + } + if (status.currentUserRetweetId > 0) { + retweetedTweet.retweets.put(myUserId, status.currentUserRetweetId) + } + } else { + if (favoriteCount != status.favoriteCount || retweetCount != status.retweetCount) { + favoriteCount = status.favoriteCount + retweetCount = status.retweetCount + notifyChange(RBinding.REACTION_COUNT) + } + + if (status.isFavorited) + favoriters.add(myUserId) + else + favoriters.remove(myUserId) + if (status.currentUserRetweetId > 0) + retweets.put(myUserId, status.currentUserRetweetId) + } + } + + val twitterUrl: String + get() = String.format("https://twitter.com/%s/status/%s", user.screenName, id) + + fun isFavoritedBy(id: Long): Boolean { + return originalTweet.favoriters.contains(id) + } + + fun addFavoriter(id: Long): Boolean { + val changed = originalTweet.favoriters.add(id) + if (changed) notifyChange(RBinding.FAVORITERS) + return changed + } + + fun removeFavoriter(id: Long): Boolean { + val changed = originalTweet.favoriters.remove(id) + if (changed) notifyChange(RBinding.FAVORITERS) + return changed + } + + fun isRetweetedBy(id: Long): Boolean { + return originalTweet.retweets[id] != null + } + + fun getRetweetIdBy(id: Long): Long { + return originalTweet.retweets[id]!! + } + + // helper methods:: + val embeddedStatusIDs: List + get() { + val list = ArrayList() + for (url in urlsExpanded) { + val uri = Uri.parse(url) + if ("twitter.com" == uri.host) { + val arr = uri.toString().split("/".toRegex()).dropLastWhile({ it.isEmpty() }).toTypedArray() + if (arr.size > 2 && "status" == arr[arr.size - 2]) { + list.add(java.lang.Long.parseLong(arr[arr.size - 1].split("\\?".toRegex()).dropLastWhile({ it.isEmpty() }).toTypedArray()[0])) + } + } + } + return list + } + + // override EntitySupport + override var mentions: List + get() = if (isRetweet) originalTweet.mentions else super.mentions + set(value) { + super.mentions = value + } + + override var hashtags: List + get() = if (isRetweet) originalTweet.hashtags else super.hashtags + set(value) { + super.hashtags = value + } + + override var mediaUrls: List + get() = if (isRetweet) { + originalTweet.mediaUrls + } else { + super.mediaUrls + } + set(value) { + super.mediaUrls = value + } + + override var urlsExpanded: List + get() = if (isRetweet) { + originalTweet.urlsExpanded + } else { + super.urlsExpanded + } + set(value) { + super.urlsExpanded = value + } + + override var symbols: List + get() = if (isRetweet) { + originalTweet.symbols + } else { + super.symbols + } + set(value) { + super.symbols = value + } + + companion object { + private val storage = HashMap() + + @Synchronized + fun fetch(statusId: Long): Tweet? { + return storage[statusId] + } + + @Synchronized + fun fetchTask(statusId: Long, account: Account): BackgroundTask { + val tweet = fetch(statusId) + return if (tweet != null) { + object : BackgroundTask() { + @Throws(Exception::class) + override fun doInBackground(): Tweet { + return tweet + } + } + } else { + Tweets.GetTask(account, statusId) + } + } + + @Synchronized + fun fromTwitter(st: twitter4j.Status, myUserId: Long): Tweet { + var t = fetch(st.id) + if (t == null) { + t = Tweet(st, myUserId) + storage.put(st.id, t) + } else { + t.update(st, myUserId) + } + return t + } + + @Synchronized + fun fromTwitter(sts: List, myUserId: Long): List { + return sts.map { st -> fromTwitter(st, myUserId) } + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/entity/User.java b/app/src/main/java/net/lacolaco/smileessence/entity/User.java deleted file mode 100644 index abc2c047..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/entity/User.java +++ /dev/null @@ -1,183 +0,0 @@ -package net.lacolaco.smileessence.entity; - -import net.lacolaco.smileessence.util.UIObservable; - -import java.util.HashMap; -import java.util.Map; - -public class User extends UIObservable implements IdObject { - private static Map storage = new HashMap<>(); - private long id; - private boolean isProtected; - private String screenName; - private String name; - private String profileImageUrl; - private String profileBannerUrl; - private String description; - private String location; - private String url; - private int favoritesCount; - private int statusesCount; - private int friendsCount; - private int followersCount; - private boolean isVerified; - - private User() { - } - - public synchronized static User fetch(long userId) { - return storage.get(userId); - } - - public synchronized static User fromTwitter(final twitter4j.User st) { - User u = fetch(st.getId()); - if (u == null) { - u = new User(); - storage.put(st.getId(), u); - } - - u.update(st); - return u; - } - - // only for initialization; DO NOT have reference for this object - public synchronized static User _makeSkeleton(long id, String screenName) { - User u = fetch(id); - if (u != null) { - return u; - } else { - u = new User(); - u.id = id; - u.screenName = screenName; - storage.put(id, u); - return u; - } - } - - private void update(twitter4j.User user) { - id = user.getId(); - - if (isProtected() != user.isProtected() || - getScreenName() == null || !getScreenName().equals(user.getScreenName()) || - getName() == null || !getName().equals(user.getName()) || - profileImageUrl == null || !profileImageUrl.equals(user.getProfileImageURLHttps())) { - isProtected = user.isProtected(); - if (user.getScreenName() != null) - screenName = user.getScreenName(); - if (user.getName() != null) - name = user.getName(); - if (user.getProfileImageURLHttps() != null) - profileImageUrl = user.getProfileImageURLHttps(); - - notifyChange(RBinding.BASIC); - } - - if (getProfileBannerUrl() == null || !getProfileBannerUrl().equals(user.getProfileBannerURL()) || - getDescription() == null || !getDescription().equals(user.getDescription()) || - getLocation() == null || !getLocation().equals(user.getLocation()) || - getUrl() == null || !getUrl().equals(user.getURL()) || - getFavoritesCount() != user.getFavouritesCount() || - getStatusesCount() != user.getStatusesCount() || - getFriendsCount() != user.getFriendsCount() || - getFollowersCount() != user.getFollowersCount()) { - isVerified = user.isVerified(); - if (user.getProfileBannerURL() != null) - profileBannerUrl = user.getProfileBannerURL(); - if (user.getDescription() != null) - description = user.getDescription(); - if (user.getLocation() != null) - location = user.getLocation(); - if (user.getURL() != null) - url = user.getURL(); - if (user.getFavouritesCount() != -1) - favoritesCount = user.getFavouritesCount(); - if (user.getStatusesCount() != -1) - statusesCount = user.getStatusesCount(); - if (user.getFriendsCount() != -1) - friendsCount = user.getFriendsCount(); - if (user.getFollowersCount() != -1) - followersCount = user.getFollowersCount(); - - notifyChange(RBinding.DETAIL); - } - } - - @Override - public long getId() { - return id; - } - - public boolean isProtected() { - return isProtected; - } - - public String getScreenName() { - return screenName; - } - - public String getName() { - return name; - } - - public String getProfileImageUrlOriginal() { - String original = profileImageUrl; - if (original != null) { - String url = original.substring(0, original.lastIndexOf("_")); - int extIndex = original.lastIndexOf("."); - if (extIndex > original.lastIndexOf("/")) { - url += original.substring(extIndex); - } - return url; - } - return null; - } - - public String getProfileBannerUrl() { - return profileBannerUrl; - } - - public String getDescription() { - return description; - } - - public String getLocation() { - return location; - } - - public String getUrl() { - return url; - } - - public int getFavoritesCount() { - return favoritesCount; - } - - public int getStatusesCount() { - return statusesCount; - } - - public int getFriendsCount() { - return friendsCount; - } - - public int getFollowersCount() { - return followersCount; - } - - public boolean isVerified() { - return isVerified; - } - - // helper methods - public String getUserHomeURL() { - return String.format("https://twitter.com/%s", getScreenName()); - } - - public String getAclogTimelineURL() { - return String.format("https://aclog.rhe.jp/%s/timeline", getScreenName()); - } - - public String getFormattedName() { - return screenName + " / " + name; - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/entity/User.kt b/app/src/main/java/net/lacolaco/smileessence/entity/User.kt new file mode 100644 index 00000000..6a92b54e --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/entity/User.kt @@ -0,0 +1,136 @@ +package net.lacolaco.smileessence.entity + +import net.lacolaco.smileessence.util.UIObservable + +import java.util.HashMap + +class User private constructor(override val id: Long, screenName: String) : UIObservable(), IdObject { + var screenName = screenName + private set + var name: String? = null + private set + var profileImageUrl: String? = null + get() { + val original = field + if (original != null) { + var url = original.substring(0, original.lastIndexOf("_")) + val extIndex = original.lastIndexOf(".") + if (extIndex > original.lastIndexOf("/")) { + url += original.substring(extIndex) + } + return url + } + return null + } + private set + var profileBannerUrl: String? = null + private set + var description: String? = null + private set + var location: String? = null + private set + var url: String? = null + private set + var favoritesCount: Int = 0 + private set + var statusesCount: Int = 0 + private set + var friendsCount: Int = 0 + private set + var followersCount: Int = 0 + private set + var isProtected: Boolean = false + private set + var isVerified: Boolean = false + private set + + private fun update(user: twitter4j.User) { + if (isProtected != user.isProtected || + screenName != user.screenName || + name == null || name != user.name || + this.profileImageUrl == null || this.profileImageUrl != user.profileImageURLHttps) { + isProtected = user.isProtected + if (user.screenName != null) + screenName = user.screenName + if (user.name != null) + name = user.name + if (user.profileImageURLHttps != null) + this.profileImageUrl = user.profileImageURLHttps + + notifyChange(RBinding.BASIC) + } + + if (profileBannerUrl == null || profileBannerUrl != user.profileBannerURL || + description == null || description != user.description || + location == null || location != user.location || + url == null || url != user.url || + favoritesCount != user.favouritesCount || + statusesCount != user.statusesCount || + friendsCount != user.friendsCount || + followersCount != user.followersCount) { + isVerified = user.isVerified + if (user.profileBannerURL != null) + profileBannerUrl = user.profileBannerURL + if (user.description != null) + description = user.description + if (user.location != null) + location = user.location + if (user.url != null) + url = user.url + if (user.favouritesCount != -1) + favoritesCount = user.favouritesCount + if (user.statusesCount != -1) + statusesCount = user.statusesCount + if (user.friendsCount != -1) + friendsCount = user.friendsCount + if (user.followersCount != -1) + followersCount = user.followersCount + + notifyChange(RBinding.DETAIL) + } + } + + // helper methods + val userHomeURL: String + get() = String.format("https://twitter.com/%s", screenName) + + val aclogTimelineURL: String + get() = String.format("https://aclog.rhe.jp/%s/timeline", screenName) + + val formattedName: String + get() = screenName + " / " + name + + companion object { + private val storage = HashMap() + + @Synchronized + fun fetch(userId: Long): User? { + return storage[userId] + } + + @Synchronized + fun fromTwitter(st: twitter4j.User): User { + var u: User? = fetch(st.id) + if (u == null) { + u = User(st.id, st.screenName) + storage.put(st.id, u) + } + + u.update(st) + return u + } + + // only for initialization; DO NOT have reference for this object + @Synchronized + fun _makeSkeleton(id: Long, screenName: String): User { + var u: User? = fetch(id) + if (u != null) { + return u + } else { + u = User(id, screenName) + storage.put(id, u) + return u + } + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/logging/Logger.java b/app/src/main/java/net/lacolaco/smileessence/logging/Logger.java deleted file mode 100644 index 675a14f1..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/logging/Logger.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.logging; - -import android.util.Log; - -public class Logger { - - // ------------------------------ FIELDS ------------------------------ - - private static final String TAG = "SmileEssence"; - - // -------------------------- STATIC METHODS -------------------------- - - public static void debug(Object message) { - Log.d(getTag(), String.valueOf(message)); - } - - public static void info(Object message) { - Log.i(getTag(), String.valueOf(message)); - } - - public static void error(Object message) { - Log.e(getTag(), String.valueOf(message)); - } - - public static void warn(Object message) { - Log.w(getTag(), String.valueOf(message)); - } - - public static void verbose(Object message) { - Log.v(getTag(), String.valueOf(message)); - } - - private static String getTag() { - StackTraceElement[] st = Thread.currentThread().getStackTrace(); - for (int i = 0; i < st.length; ++i) { - if ("getTag".equals(st[i].getMethodName())) { - return st[i + 2].getClassName() + ":" + st[i + 2].getMethodName(); - } - } - return TAG; - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/logging/Logger.kt b/app/src/main/java/net/lacolaco/smileessence/logging/Logger.kt new file mode 100644 index 00000000..7e898c1b --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/logging/Logger.kt @@ -0,0 +1,67 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.logging + +import android.util.Log + +object Logger { + + // ------------------------------ FIELDS ------------------------------ + + private val TAG = "SmileEssence" + + // -------------------------- STATIC METHODS -------------------------- + + fun debug(message: Any) { + Log.d(tag, message.toString()) + } + + fun info(message: Any) { + Log.i(tag, message.toString()) + } + + fun error(message: Any) { + Log.e(tag, message.toString()) + } + + fun warn(message: Any) { + Log.w(tag, message.toString()) + } + + fun verbose(message: Any) { + Log.v(tag, message.toString()) + } + + private val tag: String + get() { + val st = Thread.currentThread().stackTrace + for (i in st.indices) { + if ("getTag" == st[i].methodName) { + return st[i + 2].className + ":" + st[i + 2].methodName + } + } + return TAG + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/preference/InternalPreferenceHelper.java b/app/src/main/java/net/lacolaco/smileessence/preference/InternalPreferenceHelper.java deleted file mode 100644 index 9d500cd4..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/preference/InternalPreferenceHelper.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.preference; - -import android.content.Context; -import android.content.SharedPreferences; -import net.lacolaco.smileessence.Application; - -public class InternalPreferenceHelper extends SharedPreferenceHelper { - - // ------------------------------ FIELDS ------------------------------ - - private static final String FILE_NAME = "AppPreference"; - private static final InternalPreferenceHelper instance = new InternalPreferenceHelper(); - - private InternalPreferenceHelper() { - } - - public static InternalPreferenceHelper getInstance() { - return instance; - } - - // --------------------------- OVERRIDE --------------------------- - @Override - protected SharedPreferences getPreferences() { - return Application.getInstance().getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/preference/InternalPreferenceHelper.kt b/app/src/main/java/net/lacolaco/smileessence/preference/InternalPreferenceHelper.kt new file mode 100644 index 00000000..1353eb2a --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/preference/InternalPreferenceHelper.kt @@ -0,0 +1,44 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.preference + +import android.content.Context +import android.content.SharedPreferences +import net.lacolaco.smileessence.Application + +class InternalPreferenceHelper private constructor() : SharedPreferenceHelper() { + + // --------------------------- OVERRIDE --------------------------- + override val preferences: SharedPreferences + get() = Application.getInstance().getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE) + + companion object { + + // ------------------------------ FIELDS ------------------------------ + + private val FILE_NAME = "AppPreference" + val instance = InternalPreferenceHelper() + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/preference/SharedPreferenceHelper.java b/app/src/main/java/net/lacolaco/smileessence/preference/SharedPreferenceHelper.java deleted file mode 100644 index 979dc732..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/preference/SharedPreferenceHelper.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.preference; - -import android.content.SharedPreferences; -import net.lacolaco.smileessence.Application; - -import java.util.Set; - -public abstract class SharedPreferenceHelper { - // --------------------- GETTER / SETTER METHODS --------------------- - - protected abstract SharedPreferences getPreferences(); - - // -------------------------- OTHER METHODS -------------------------- - - public String get(int key, String defaultValue) { - return getPreferences().getString(getString(key), defaultValue); - } - - // int, long, float value may be stored in String format (old versions) - public int get(int key, int defaultValue) { - try { - return getPreferences().getInt(getString(key), defaultValue); - } catch (ClassCastException ex) { - int ret = Integer.parseInt(get(key, String.valueOf(defaultValue))); - set(key, ret); - return ret; - } - } - - public long get(int key, long defaultValue) { - try { - return getPreferences().getLong(getString(key), defaultValue); - } catch (ClassCastException ex) { - long ret = Long.parseLong(get(key, String.valueOf(defaultValue))); - set(key, ret); - return ret; - } - } - - public float get(int key, float defaultValue) { - try { - return getPreferences().getFloat(getString(key), defaultValue); - } catch (ClassCastException ex) { - float ret = Float.parseFloat(get(key, String.valueOf(defaultValue))); - set(key, ret); - return ret; - } - } - - public boolean get(int key, boolean defaultValue) { - return getPreferences().getBoolean(getString(key), defaultValue); - } - - public Set get(int key, Set defaultValue) { - return getPreferences().getStringSet(getString(key), defaultValue); - } - - public boolean set(int key, String value) { - return getPreferences().edit() - .putString(getString(key), value) - .commit(); - } - - public boolean set(int key, int value) { - return getPreferences().edit() - .putInt(getString(key), value) - .commit(); - } - - public boolean set(int key, long value) { - return getPreferences().edit() - .putLong(getString(key), value) - .commit(); - } - - public boolean set(int key, float value) { - return getPreferences().edit() - .putFloat(getString(key), value) - .commit(); - } - - public boolean set(int key, boolean value) { - return getPreferences().edit() - .putBoolean(getString(key), value) - .commit(); - } - - public boolean set(int key, Set value) { - return getPreferences().edit() - .putStringSet(getString(key), value) - .commit(); - } - - private String getString(int resID) { - try { - return Application.getInstance().getString(resID); - } catch (Exception e) { - return null; - } - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/preference/SharedPreferenceHelper.kt b/app/src/main/java/net/lacolaco/smileessence/preference/SharedPreferenceHelper.kt new file mode 100644 index 00000000..6702f1c3 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/preference/SharedPreferenceHelper.kt @@ -0,0 +1,127 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.preference + +import android.content.SharedPreferences +import net.lacolaco.smileessence.Application + +abstract class SharedPreferenceHelper { + // --------------------- GETTER / SETTER METHODS --------------------- + + protected abstract val preferences: SharedPreferences + + // -------------------------- OTHER METHODS -------------------------- + + operator fun get(key: Int, defaultValue: String): String { + return preferences.getString(getString(key), defaultValue) + } + + // int, long, float value may be stored in String format (old versions) + operator fun get(key: Int, defaultValue: Int): Int { + try { + return preferences.getInt(getString(key), defaultValue) + } catch (ex: ClassCastException) { + val ret = Integer.parseInt(get(key, defaultValue.toString())) + set(key, ret) + return ret + } + + } + + operator fun get(key: Int, defaultValue: Long): Long { + try { + return preferences.getLong(getString(key), defaultValue) + } catch (ex: ClassCastException) { + val ret = java.lang.Long.parseLong(get(key, defaultValue.toString())) + set(key, ret) + return ret + } + + } + + operator fun get(key: Int, defaultValue: Float): Float { + try { + return preferences.getFloat(getString(key), defaultValue) + } catch (ex: ClassCastException) { + val ret = java.lang.Float.parseFloat(get(key, defaultValue.toString())) + set(key, ret) + return ret + } + + } + + operator fun get(key: Int, defaultValue: Boolean): Boolean { + return preferences.getBoolean(getString(key), defaultValue) + } + + operator fun get(key: Int, defaultValue: Set): Set { + return preferences.getStringSet(getString(key), defaultValue) + } + + operator fun set(key: Int, value: String): Boolean { + return preferences.edit() + .putString(getString(key), value) + .commit() + } + + operator fun set(key: Int, value: Int): Boolean { + return preferences.edit() + .putInt(getString(key), value) + .commit() + } + + operator fun set(key: Int, value: Long): Boolean { + return preferences.edit() + .putLong(getString(key), value) + .commit() + } + + operator fun set(key: Int, value: Float): Boolean { + return preferences.edit() + .putFloat(getString(key), value) + .commit() + } + + operator fun set(key: Int, value: Boolean): Boolean { + return preferences.edit() + .putBoolean(getString(key), value) + .commit() + } + + operator fun set(key: Int, value: Set): Boolean { + return preferences.edit() + .putStringSet(getString(key), value) + .commit() + } + + private fun getString(resID: Int): String? { + try { + return Application.getInstance().getString(resID) + } catch (e: Exception) { + return null + } + + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/preference/UserPreferenceHelper.java b/app/src/main/java/net/lacolaco/smileessence/preference/UserPreferenceHelper.java deleted file mode 100644 index e3eb95ea..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/preference/UserPreferenceHelper.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.preference; - -import android.content.SharedPreferences; -import android.preference.PreferenceManager; -import net.lacolaco.smileessence.Application; -import net.lacolaco.smileessence.R; - -public class UserPreferenceHelper extends SharedPreferenceHelper { - // --------------------------- CONSTRUCTORS --------------------------- - - private static final UserPreferenceHelper instance = new UserPreferenceHelper(); - - private UserPreferenceHelper() { - } - - public static UserPreferenceHelper getInstance() { - return instance; - } - - // --------------------- GETTER / SETTER METHODS --------------------- - @Override - protected SharedPreferences getPreferences() { - return PreferenceManager.getDefaultSharedPreferences(Application.getInstance()); - } - - // --------------------- HELPER METHODS --------------------- - public int getThemeIndex() { - return get(R.string.key_setting_theme, 0); - } - - public int getTextSize() { - return get(R.string.key_setting_text_size, 10); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/preference/UserPreferenceHelper.kt b/app/src/main/java/net/lacolaco/smileessence/preference/UserPreferenceHelper.kt new file mode 100644 index 00000000..41f7f019 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/preference/UserPreferenceHelper.kt @@ -0,0 +1,50 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.preference + +import android.content.SharedPreferences +import android.preference.PreferenceManager +import net.lacolaco.smileessence.Application +import net.lacolaco.smileessence.R + +class UserPreferenceHelper private constructor() : SharedPreferenceHelper() { + + // --------------------- GETTER / SETTER METHODS --------------------- + override val preferences: SharedPreferences + get() = PreferenceManager.getDefaultSharedPreferences(Application.getInstance()) + + // --------------------- HELPER METHODS --------------------- + val themeIndex: Int + get() = get(R.string.key_setting_theme, 0) + + val textSize: Int + get() = get(R.string.key_setting_text_size, 10) + + companion object { + // --------------------------- CONSTRUCTORS --------------------------- + + val instance = UserPreferenceHelper() + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/twitter/OAuthSession.java b/app/src/main/java/net/lacolaco/smileessence/twitter/OAuthSession.java deleted file mode 100644 index 160e710a..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/twitter/OAuthSession.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.twitter; - -import net.lacolaco.smileessence.twitter.task.Accounts; -import twitter4j.Twitter; -import twitter4j.TwitterFactory; -import twitter4j.auth.AccessToken; -import twitter4j.auth.RequestToken; - -public class OAuthSession { - public static final String KEY_TOKEN = "token"; - public static final String KEY_TOKEN_SECRET = "tokenSecret"; - public static final String KEY_SCREEN_NAME = "screenName"; - public static final String KEY_USER_ID = "userID"; - private RequestToken requestToken; - - // --------------------- GETTER / SETTER METHODS --------------------- - - public String getAuthorizationURL() { - Twitter twitter = new TwitterFactory().getInstance(); - Accounts.RequestTokenTask task = new Accounts.RequestTokenTask(twitter); - task.execute(); - try { - requestToken = task.getImmediately(); - return requestToken.getAuthorizationURL(); - } catch (Exception e) { - return null; - } - } - - // -------------------------- OTHER METHODS -------------------------- - - public AccessToken getAccessToken(String pinCode) { - Twitter twitter = new TwitterFactory().getInstance(); - Accounts.AccessTokenTask task = new Accounts.AccessTokenTask(twitter, requestToken, pinCode); - task.execute(); - try { - return task.getImmediately(); - } catch (Exception e) { - return null; - } - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/twitter/OAuthSession.kt b/app/src/main/java/net/lacolaco/smileessence/twitter/OAuthSession.kt new file mode 100644 index 00000000..63a0c484 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/twitter/OAuthSession.kt @@ -0,0 +1,72 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.twitter + +import net.lacolaco.smileessence.twitter.task.Accounts +import twitter4j.Twitter +import twitter4j.TwitterFactory +import twitter4j.auth.AccessToken +import twitter4j.auth.RequestToken + +class OAuthSession { + private var requestToken: RequestToken? = null + + // --------------------- GETTER / SETTER METHODS --------------------- + + val authorizationURL: String? + get() { + val twitter = TwitterFactory().instance + val task = Accounts.RequestTokenTask(twitter) + task.execute() + try { + requestToken = task.immediately + return requestToken!!.authorizationURL + } catch (e: Exception) { + return null + } + + } + + // -------------------------- OTHER METHODS -------------------------- + + fun getAccessToken(pinCode: String): AccessToken? { + val twitter = TwitterFactory().instance + val task = Accounts.AccessTokenTask(twitter, requestToken!!, pinCode) + task.execute() + try { + return task.immediately + } catch (e: Exception) { + return null + } + + } + + companion object { + val KEY_TOKEN = "token" + val KEY_TOKEN_SECRET = "tokenSecret" + val KEY_SCREEN_NAME = "screenName" + val KEY_USER_ID = "userID" + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/twitter/UserStreamListener.java b/app/src/main/java/net/lacolaco/smileessence/twitter/UserStreamListener.java deleted file mode 100644 index acfb44be..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/twitter/UserStreamListener.java +++ /dev/null @@ -1,235 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.twitter; - -import net.lacolaco.smileessence.R; -import net.lacolaco.smileessence.World; -import net.lacolaco.smileessence.entity.DirectMessage; -import net.lacolaco.smileessence.entity.Event; -import net.lacolaco.smileessence.entity.Tweet; -import net.lacolaco.smileessence.entity.User; -import net.lacolaco.smileessence.logging.Logger; -import twitter4j.ConnectionLifeCycleListener; -import twitter4j.Status; -import twitter4j.StatusDeletionNotice; - -public class UserStreamListener implements twitter4j.UserStreamListener, ConnectionLifeCycleListener { - private final World world; - private boolean connected = false; - - public UserStreamListener(World world) { - this.world = world; - } - - public boolean isConnected() { - return connected; - } - - @Override - public void onConnect() { - connected = true; - world.notify(R.string.notice_stream_connect); - } - - @Override - public void onDisconnect() { - connected = false; - world.notify(R.string.notice_stream_disconnect); - } - - @Override - public void onCleanUp() { - } - - // --------------------- Interface StatusListener --------------------- - - @Override - public void onStatus(Status status) { - User user = world.getAccount().getUser(); - Tweet tweet = Tweet.fromTwitter(status, user.getId()); - world.addTweet(tweet); - if (tweet.isRetweet()) { - if (tweet.getOriginalTweet().getUser().getId() == user.getId()) { - addToHistory(new Event(Event.EnumEvent.RETWEETED, tweet.getUser(), tweet)); - } - } else if (tweet.getMentions().contains(user.getScreenName())) { - Event mentioned = new Event(Event.EnumEvent.MENTIONED, tweet.getUser(), tweet); - world.notify(mentioned.getFormattedString()); - } - } - - @Override - public void onDeletionNotice(StatusDeletionNotice statusDeletionNotice) { - // FIXME - // StatusFilter.getInstance().remove(StatusViewModel.class, statusDeletionNotice.getStatusId()); - // Tweet.remove(statusDeletionNotice.getStatusId()); - } - - @Override - public void onTrackLimitationNotice(int numberOfLimitedStatuses) { - } - - @Override - public void onScrubGeo(long userId, long upToStatusId) { - } - - @Override - public void onStallWarning(twitter4j.StallWarning warning) { - } - - // --------------------- Interface StreamListener --------------------- - - @Override - public void onException(Exception ex) { - Logger.error(ex.toString()); - } - - // --------------------- Interface UserStreamListener --------------------- - - @Override - public void onDeletionNotice(long directMessageId, long userId) { - // FIXME - // StatusFilter.getInstance().remove(MessageViewModel.class, directMessageId); - // DirectMessage.remove(directMessageId); - } - - @Override - public void onFriendList(long[] friendIds) { - } - - @Override - public void onFavorite(twitter4j.User source, twitter4j.User target, Status favoritedStatus) { - Tweet tweet = Tweet.fromTwitter(favoritedStatus, world.getAccount().getUserId()); - tweet.addFavoriter(source.getId()); - if (User.fromTwitter(target) == world.getAccount().getUser()) { - addToHistory(new Event(Event.EnumEvent.FAVORITED, User.fromTwitter(source), tweet)); - } - } - - @Override - public void onUnfavorite(twitter4j.User source, twitter4j.User target, twitter4j.Status unfavoritedStatus) { - Tweet tweet = Tweet.fromTwitter(unfavoritedStatus, world.getAccount().getUserId()); - tweet.removeFavoriter(source.getId()); - if (User.fromTwitter(target) == world.getAccount().getUser()) { - addToHistory(new Event(Event.EnumEvent.UNFAVORITED, User.fromTwitter(source), tweet)); - } - } - - @Override - public void onFollow(twitter4j.User source, twitter4j.User followedUser) { - if (User.fromTwitter(followedUser) == world.getAccount().getUser()) { - addToHistory(new Event(Event.EnumEvent.FOLLOWED, User.fromTwitter(source))); - } - } - - @Override - public void onUnfollow(twitter4j.User source, twitter4j.User unfollowedUser) { - } - - @Override - public void onDirectMessage(twitter4j.DirectMessage directMessage) { - DirectMessage message = DirectMessage.fromTwitter(directMessage); - world.addDirectMessage(message); - if (message.getRecipient() == world.getAccount().getUser()) { - addToHistory(new Event(Event.EnumEvent.RECEIVE_MESSAGE, message.getSender())); - } - } - - @Override - public void onUserListMemberAddition(twitter4j.User addedMember, twitter4j.User listOwner, twitter4j.UserList list) { - } - - @Override - public void onUserListMemberDeletion(twitter4j.User deletedMember, twitter4j.User listOwner, twitter4j.UserList list) { - } - - @Override - public void onUserListSubscription(twitter4j.User subscriber, twitter4j.User listOwner, twitter4j.UserList list) { - world.addListSubscription(list.getFullName()); - } - - @Override - public void onUserListUnsubscription(twitter4j.User subscriber, twitter4j.User listOwner, twitter4j.UserList list) { - world.removeListSubscription(list.getFullName()); - } - - @Override - public void onUserListCreation(twitter4j.User listOwner, twitter4j.UserList list) { - world.addListSubscription(list.getFullName()); - } - - @Override - public void onUserListUpdate(twitter4j.User listOwner, twitter4j.UserList list) { - } - - @Override - public void onUserListDeletion(twitter4j.User listOwner, twitter4j.UserList list) { - world.removeListSubscription(list.getFullName()); - } - - @Override - public void onUserProfileUpdate(twitter4j.User updatedUser) { - User.fromTwitter(updatedUser); - } - - @Override - public void onUserSuspension(long suspendedUser) { - } - - @Override - public void onUserDeletion(long deletedUser) { - } - - @Override - public void onBlock(twitter4j.User source, twitter4j.User blockedUser) { - if (User.fromTwitter(blockedUser) == world.getAccount().getUser()) { - addToHistory(new Event(Event.EnumEvent.BLOCKED, User.fromTwitter(source))); - } - } - - @Override - public void onUnblock(twitter4j.User source, twitter4j.User unblockedUser) { - if (User.fromTwitter(unblockedUser) == world.getAccount().getUser()) { - addToHistory(new Event(Event.EnumEvent.UNBLOCKED, User.fromTwitter(source))); - } - } - - @Override - public void onRetweetedRetweet(twitter4j.User source, twitter4j.User target, twitter4j.Status retweetedStatus) { - } - - @Override - public void onFavoritedRetweet(twitter4j.User source, twitter4j.User target, twitter4j.Status favoritedRetweeet) { - } - - @Override - public void onQuotedTweet(twitter4j.User source, twitter4j.User target, twitter4j.Status quotingTweet) { - } - - private void addToHistory(Event mentioned) { - world.addEvent(mentioned); - world.notify(mentioned.getFormattedString()); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/twitter/UserStreamListener.kt b/app/src/main/java/net/lacolaco/smileessence/twitter/UserStreamListener.kt new file mode 100644 index 00000000..80a0c808 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/twitter/UserStreamListener.kt @@ -0,0 +1,182 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.twitter + +import net.lacolaco.smileessence.R +import net.lacolaco.smileessence.World +import net.lacolaco.smileessence.entity.DirectMessage +import net.lacolaco.smileessence.entity.Event +import net.lacolaco.smileessence.entity.Tweet +import net.lacolaco.smileessence.entity.User +import net.lacolaco.smileessence.logging.Logger +import twitter4j.ConnectionLifeCycleListener +import twitter4j.Status +import twitter4j.StatusDeletionNotice + +class UserStreamListener(private val world: World) : twitter4j.UserStreamListener, ConnectionLifeCycleListener { + var isConnected = false + private set + + override fun onConnect() { + isConnected = true + world.notify(R.string.notice_stream_connect) + } + + override fun onDisconnect() { + isConnected = false + world.notify(R.string.notice_stream_disconnect) + } + + override fun onCleanUp() {} + + // --------------------- Interface StatusListener --------------------- + + override fun onStatus(status: Status) { + val user = world.account.user + val tweet = Tweet.fromTwitter(status, user.id) + world.addTweet(tweet) + if (tweet.isRetweet) { + if (tweet.originalTweet.user.id == user.id) { + addToHistory(Event(Event.EnumEvent.RETWEETED, tweet.user, tweet)) + } + } else if (tweet.mentions.contains(user.screenName)) { + val mentioned = Event(Event.EnumEvent.MENTIONED, tweet.user, tweet) + world.notify(mentioned.formattedString) + } + } + + override fun onDeletionNotice(statusDeletionNotice: StatusDeletionNotice) { + // FIXME + // StatusFilter.getInstance().remove(StatusViewModel.class, statusDeletionNotice.getStatusId()); + // Tweet.remove(statusDeletionNotice.getStatusId()); + } + + override fun onTrackLimitationNotice(numberOfLimitedStatuses: Int) {} + + override fun onScrubGeo(userId: Long, upToStatusId: Long) {} + + override fun onStallWarning(warning: twitter4j.StallWarning) {} + + // --------------------- Interface StreamListener --------------------- + + override fun onException(ex: Exception) { + Logger.error(ex.toString()) + } + + // --------------------- Interface UserStreamListener --------------------- + + override fun onDeletionNotice(directMessageId: Long, userId: Long) { + // FIXME + // StatusFilter.getInstance().remove(MessageViewModel.class, directMessageId); + // DirectMessage.remove(directMessageId); + } + + override fun onFriendList(friendIds: LongArray) {} + + override fun onFavorite(source: twitter4j.User, target: twitter4j.User, favoritedStatus: Status) { + val tweet = Tweet.fromTwitter(favoritedStatus, world.account.userId) + tweet.addFavoriter(source.id) + if (User.fromTwitter(target) === world.account.user) { + addToHistory(Event(Event.EnumEvent.FAVORITED, User.fromTwitter(source), tweet)) + } + } + + override fun onUnfavorite(source: twitter4j.User, target: twitter4j.User, unfavoritedStatus: twitter4j.Status) { + val tweet = Tweet.fromTwitter(unfavoritedStatus, world.account.userId) + tweet.removeFavoriter(source.id) + if (User.fromTwitter(target) === world.account.user) { + addToHistory(Event(Event.EnumEvent.UNFAVORITED, User.fromTwitter(source), tweet)) + } + } + + override fun onFollow(source: twitter4j.User, followedUser: twitter4j.User) { + if (User.fromTwitter(followedUser) === world.account.user) { + addToHistory(Event(Event.EnumEvent.FOLLOWED, User.fromTwitter(source))) + } + } + + override fun onUnfollow(source: twitter4j.User, unfollowedUser: twitter4j.User) {} + + override fun onDirectMessage(directMessage: twitter4j.DirectMessage) { + val message = DirectMessage.fromTwitter(directMessage) + world.addDirectMessage(message) + if (message.recipient === world.account.user) { + addToHistory(Event(Event.EnumEvent.RECEIVE_MESSAGE, message.sender)) + } + } + + override fun onUserListMemberAddition(addedMember: twitter4j.User, listOwner: twitter4j.User, list: twitter4j.UserList) {} + + override fun onUserListMemberDeletion(deletedMember: twitter4j.User, listOwner: twitter4j.User, list: twitter4j.UserList) {} + + override fun onUserListSubscription(subscriber: twitter4j.User, listOwner: twitter4j.User, list: twitter4j.UserList) { + world.addListSubscription(list.fullName) + } + + override fun onUserListUnsubscription(subscriber: twitter4j.User, listOwner: twitter4j.User, list: twitter4j.UserList) { + world.removeListSubscription(list.fullName) + } + + override fun onUserListCreation(listOwner: twitter4j.User, list: twitter4j.UserList) { + world.addListSubscription(list.fullName) + } + + override fun onUserListUpdate(listOwner: twitter4j.User, list: twitter4j.UserList) {} + + override fun onUserListDeletion(listOwner: twitter4j.User, list: twitter4j.UserList) { + world.removeListSubscription(list.fullName) + } + + override fun onUserProfileUpdate(updatedUser: twitter4j.User) { + User.fromTwitter(updatedUser) + } + + override fun onUserSuspension(suspendedUser: Long) {} + + override fun onUserDeletion(deletedUser: Long) {} + + override fun onBlock(source: twitter4j.User, blockedUser: twitter4j.User) { + if (User.fromTwitter(blockedUser) === world.account.user) { + addToHistory(Event(Event.EnumEvent.BLOCKED, User.fromTwitter(source))) + } + } + + override fun onUnblock(source: twitter4j.User, unblockedUser: twitter4j.User) { + if (User.fromTwitter(unblockedUser) === world.account.user) { + addToHistory(Event(Event.EnumEvent.UNBLOCKED, User.fromTwitter(source))) + } + } + + override fun onRetweetedRetweet(source: twitter4j.User, target: twitter4j.User, retweetedStatus: twitter4j.Status) {} + + override fun onFavoritedRetweet(source: twitter4j.User, target: twitter4j.User, favoritedRetweeet: twitter4j.Status) {} + + override fun onQuotedTweet(source: twitter4j.User, target: twitter4j.User, quotingTweet: twitter4j.Status) {} + + private fun addToHistory(mentioned: Event) { + world.addEvent(mentioned) + world.notify(mentioned.formattedString) + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/twitter/task/Accounts.java b/app/src/main/java/net/lacolaco/smileessence/twitter/task/Accounts.java deleted file mode 100644 index 7842e349..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/twitter/task/Accounts.java +++ /dev/null @@ -1,90 +0,0 @@ -package net.lacolaco.smileessence.twitter.task; - -import net.lacolaco.smileessence.data.Account; -import net.lacolaco.smileessence.util.BackgroundTask; -import twitter4j.IDs; -import twitter4j.Twitter; -import twitter4j.TwitterException; -import twitter4j.auth.AccessToken; -import twitter4j.auth.RequestToken; - -import java.util.ArrayList; -import java.util.List; - -public class Accounts { - public static class AccessTokenTask extends BackgroundTask { - private final Twitter twitter; - private final RequestToken requestToken; - private final String pinCode; - - public AccessTokenTask(Twitter twitter, RequestToken requestToken, String pinCode) { - this.twitter = twitter; - this.requestToken = requestToken; - this.pinCode = pinCode; - } - - @Override - protected AccessToken doInBackground() throws TwitterException { - return twitter.getOAuthAccessToken(requestToken, pinCode); - } - } - - public static class RequestTokenTask extends BackgroundTask { - private final Twitter twitter; - - public RequestTokenTask(Twitter twitter) { - this.twitter = twitter; - } - - @Override - protected RequestToken doInBackground() throws TwitterException { - return twitter.getOAuthRequestToken("oob"); - } - } - - public static class BlockIDsTask extends BackgroundTask, Void> { - private final Account account; - - public BlockIDsTask(Account account) { - this.account = account; - } - - @Override - protected List doInBackground() throws TwitterException { - List idList = new ArrayList<>(); - long cursor = -1; - - while (cursor != 0) { - IDs blocksIDs = account.getTwitter().getBlocksIDs(cursor); - cursor = blocksIDs.getNextCursor(); - for (long id : blocksIDs.getIDs()) { - idList.add(id); - } - } - - return idList; - } - } - - public static class MutesIDsTask extends BackgroundTask, Void> { - private final Account account; - - public MutesIDsTask(Account account) { - this.account = account; - } - - @Override - protected List doInBackground() throws TwitterException { - List idList = new ArrayList<>(); - long cursor = -1; - while (cursor != 0) { - IDs mutesIDs = account.getTwitter().getMutesIDs(cursor); - cursor = mutesIDs.getNextCursor(); - for (long id : mutesIDs.getIDs()) { - idList.add(id); - } - } - return idList; - } - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/twitter/task/Accounts.kt b/app/src/main/java/net/lacolaco/smileessence/twitter/task/Accounts.kt new file mode 100644 index 00000000..22a90374 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/twitter/task/Accounts.kt @@ -0,0 +1,65 @@ +package net.lacolaco.smileessence.twitter.task + +import net.lacolaco.smileessence.data.Account +import net.lacolaco.smileessence.util.BackgroundTask +import twitter4j.IDs +import twitter4j.Twitter +import twitter4j.TwitterException +import twitter4j.auth.AccessToken +import twitter4j.auth.RequestToken + +import java.util.ArrayList + +class Accounts { + class AccessTokenTask(private val twitter: Twitter, private val requestToken: RequestToken, private val pinCode: String) : BackgroundTask() { + + @Throws(TwitterException::class) + override fun doInBackground(): AccessToken { + return twitter.getOAuthAccessToken(requestToken, pinCode) + } + } + + class RequestTokenTask(private val twitter: Twitter) : BackgroundTask() { + + @Throws(TwitterException::class) + override fun doInBackground(): RequestToken { + return twitter.getOAuthRequestToken("oob") + } + } + + class BlockIDsTask(private val account: Account) : BackgroundTask, Void>() { + + @Throws(TwitterException::class) + override fun doInBackground(): List { + val idList = ArrayList() + var cursor: Long = -1 + + while (cursor != 0L) { + val blocksIDs = account.twitter.getBlocksIDs(cursor) + cursor = blocksIDs.nextCursor + for (id in blocksIDs.iDs) { + idList.add(id) + } + } + + return idList + } + } + + class MutesIDsTask(private val account: Account) : BackgroundTask, Void>() { + + @Throws(TwitterException::class) + override fun doInBackground(): List { + val idList = ArrayList() + var cursor: Long = -1 + while (cursor != 0L) { + val mutesIDs = account.twitter.getMutesIDs(cursor) + cursor = mutesIDs.nextCursor + for (id in mutesIDs.iDs) { + idList.add(id) + } + } + return idList + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/twitter/task/Messages.java b/app/src/main/java/net/lacolaco/smileessence/twitter/task/Messages.java deleted file mode 100644 index ff13a07c..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/twitter/task/Messages.java +++ /dev/null @@ -1,68 +0,0 @@ -package net.lacolaco.smileessence.twitter.task; - -import net.lacolaco.smileessence.data.Account; -import net.lacolaco.smileessence.entity.DirectMessage; -import net.lacolaco.smileessence.util.BackgroundTask; -import twitter4j.TwitterException; - -import java.util.List; - -public class Messages { - public static class CreateTask extends BackgroundTask { - private final Account account; - private final long userID; - private final String text; - - public CreateTask(Account account, long userID, String text) { - this.account = account; - this.userID = userID; - this.text = text; - } - - @Override - protected DirectMessage doInBackground() throws TwitterException { - return DirectMessage.fromTwitter(account.getTwitter().directMessages().sendDirectMessage(userID, text)); - } - } - - public static class DestroyTask extends BackgroundTask { - private final Account account; - private final long messageID; - - public DestroyTask(Account account, long messageID) { - this.account = account; - this.messageID = messageID; - } - - @Override - protected DirectMessage doInBackground() throws TwitterException { - return DirectMessage.fromTwitter(account.getTwitter().directMessages().destroyDirectMessage(messageID)); - } - } - - public static class GetAllReceived extends TimelineTask { - private final Account account; - - public GetAllReceived(Account account) { - this.account = account; - } - - @Override - protected List doInBackground() throws TwitterException { - return DirectMessage.fromTwitter(account.getTwitter().directMessages().getDirectMessages(getPaging())); - } - } - - public static class GetAllSent extends TimelineTask { - private final Account account; - - public GetAllSent(Account account) { - this.account = account; - } - - @Override - protected List doInBackground() throws TwitterException { - return DirectMessage.fromTwitter(account.getTwitter().directMessages().getSentDirectMessages(getPaging())); - } - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/twitter/task/Messages.kt b/app/src/main/java/net/lacolaco/smileessence/twitter/task/Messages.kt new file mode 100644 index 00000000..b5553c32 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/twitter/task/Messages.kt @@ -0,0 +1,40 @@ +package net.lacolaco.smileessence.twitter.task + +import net.lacolaco.smileessence.data.Account +import net.lacolaco.smileessence.entity.DirectMessage +import net.lacolaco.smileessence.util.BackgroundTask +import twitter4j.TwitterException + +class Messages { + class CreateTask(private val account: Account, private val userID: Long, private val text: String) : BackgroundTask() { + + @Throws(TwitterException::class) + override fun doInBackground(): DirectMessage { + return DirectMessage.fromTwitter(account.twitter.directMessages().sendDirectMessage(userID, text)) + } + } + + class DestroyTask(private val account: Account, private val messageID: Long) : BackgroundTask() { + + @Throws(TwitterException::class) + override fun doInBackground(): DirectMessage { + return DirectMessage.fromTwitter(account.twitter.directMessages().destroyDirectMessage(messageID)) + } + } + + class GetAllReceived(private val account: Account) : TimelineTask() { + + @Throws(TwitterException::class) + override fun doInBackground(): List { + return DirectMessage.fromTwitter(account.twitter.directMessages().getDirectMessages(paging)) + } + } + + class GetAllSent(private val account: Account) : TimelineTask() { + + @Throws(TwitterException::class) + override fun doInBackground(): List { + return DirectMessage.fromTwitter(account.twitter.directMessages().getSentDirectMessages(paging)) + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/twitter/task/Searches.java b/app/src/main/java/net/lacolaco/smileessence/twitter/task/Searches.java deleted file mode 100644 index 91f6fbcc..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/twitter/task/Searches.java +++ /dev/null @@ -1,80 +0,0 @@ -package net.lacolaco.smileessence.twitter.task; - -import net.lacolaco.smileessence.data.Account; -import net.lacolaco.smileessence.entity.SavedSearch; -import net.lacolaco.smileessence.entity.Tweet; -import net.lacolaco.smileessence.util.BackgroundTask; -import net.lacolaco.smileessence.util.ListUtils; -import twitter4j.Query; -import twitter4j.TwitterException; - -import java.util.List; - -public class Searches { - public static class CreateSavedSearchTask extends BackgroundTask { - private final Account account; - private final String query; - - public CreateSavedSearchTask(Account account, String query) { - this.account = account; - this.query = query; - } - - @Override - protected SavedSearch doInBackground() throws Exception { - return SavedSearch.fromTwitter(account.getTwitter().savedSearches().createSavedSearch(query)); - } - } - - public static class DestroySavedSearchTask extends BackgroundTask { - private final Account account; - private final long id; - - public DestroySavedSearchTask(Account account, long id) { - this.account = account; - this.id = id; - } - - @Override - protected Void doInBackground() throws Exception { - account.getTwitter().savedSearches().destroySavedSearch(id); - return null; - } - } - - public static class GetAllSavedSearchesTask extends BackgroundTask, Void> { - private final Account account; - - public GetAllSavedSearchesTask(Account account) { - this.account = account; - } - - @Override - protected List doInBackground() throws Exception { - return ListUtils.map(account.getTwitter().savedSearches().getSavedSearches(), SavedSearch::fromTwitter); - } - } - - // TODO: List is not good here - public static class SearchTask extends BackgroundTask, Void> { - - // ------------------------------ FIELDS ------------------------------ - - private final Account account; - private final Query query; - - // --------------------------- CONSTRUCTORS --------------------------- - - public SearchTask(Account account, Query query) { - this.account = account; - this.query = query; - } - - // ------------------------ OVERRIDE METHODS ------------------------ - - @Override - protected List doInBackground() throws TwitterException { - return Tweet.fromTwitter(account.getTwitter().search(query).getTweets(), account.getUserId()); - } - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/twitter/task/Searches.kt b/app/src/main/java/net/lacolaco/smileessence/twitter/task/Searches.kt new file mode 100644 index 00000000..9ea1792b --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/twitter/task/Searches.kt @@ -0,0 +1,51 @@ +package net.lacolaco.smileessence.twitter.task + +import net.lacolaco.smileessence.data.Account +import net.lacolaco.smileessence.entity.SavedSearch +import net.lacolaco.smileessence.entity.Tweet +import net.lacolaco.smileessence.util.BackgroundTask +import twitter4j.Query +import twitter4j.TwitterException + +class Searches { + class CreateSavedSearchTask(private val account: Account, private val query: String) : BackgroundTask() { + + @Throws(Exception::class) + override fun doInBackground(): SavedSearch { + return SavedSearch.fromTwitter(account.twitter.savedSearches().createSavedSearch(query)) + } + } + + class DestroySavedSearchTask(private val account: Account, private val id: Long) : BackgroundTask() { + + @Throws(Exception::class) + override fun doInBackground() { + account.twitter.savedSearches().destroySavedSearch(id) + } + } + + class GetAllSavedSearchesTask(private val account: Account) : BackgroundTask, Void>() { + + @Throws(Exception::class) + override fun doInBackground(): List { + return account.twitter.savedSearches().savedSearches.map { SavedSearch.fromTwitter(it)} + } + } + + // TODO: List is not good here + class SearchTask + // --------------------------- CONSTRUCTORS --------------------------- + + ( + // ------------------------------ FIELDS ------------------------------ + + private val account: Account, private val query: Query) : BackgroundTask, Void>() { + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Throws(TwitterException::class) + override fun doInBackground(): List { + return Tweet.fromTwitter(account.twitter.search(query).tweets, account.userId) + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/twitter/task/TimelineTask.java b/app/src/main/java/net/lacolaco/smileessence/twitter/task/TimelineTask.java deleted file mode 100644 index 1025d3e9..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/twitter/task/TimelineTask.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.twitter.task; - -import net.lacolaco.smileessence.util.BackgroundTask; -import twitter4j.Paging; - -import java.util.List; - -public abstract class TimelineTask extends BackgroundTask, Void> { - private Paging paging = new Paging(); - - public TimelineTask setCount(int count) { - paging.setCount(count); - return this; - } - - public TimelineTask setMaxId(long maxId) { - if (maxId > 0) { - paging.setMaxId(maxId); - } - return this; - } - - public TimelineTask setSinceId(long sinceId) { - if (sinceId > 0) { - paging.setSinceId(sinceId); - } - return this; - } - - protected Paging getPaging() { - return paging; - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/twitter/task/TimelineTask.kt b/app/src/main/java/net/lacolaco/smileessence/twitter/task/TimelineTask.kt new file mode 100644 index 00000000..d6b2c054 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/twitter/task/TimelineTask.kt @@ -0,0 +1,51 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.twitter.task + +import net.lacolaco.smileessence.util.BackgroundTask +import twitter4j.Paging + +abstract class TimelineTask : BackgroundTask, Void>() { + protected val paging = Paging() + + fun setCount(count: Int): TimelineTask { + paging.count = count + return this + } + + fun setMaxId(maxId: Long): TimelineTask { + if (maxId > 0) { + paging.maxId = maxId + } + return this + } + + fun setSinceId(sinceId: Long): TimelineTask { + if (sinceId > 0) { + paging.sinceId = sinceId + } + return this + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/twitter/task/Timelines.java b/app/src/main/java/net/lacolaco/smileessence/twitter/task/Timelines.java deleted file mode 100644 index ae1aa0ea..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/twitter/task/Timelines.java +++ /dev/null @@ -1,94 +0,0 @@ -package net.lacolaco.smileessence.twitter.task; - -import net.lacolaco.smileessence.data.Account; -import net.lacolaco.smileessence.entity.Tweet; -import twitter4j.TwitterException; - -import java.util.List; - -public class Timelines { - public static class HomeTimelineTask extends TimelineTask { - - // ------------------------------ FIELDS ------------------------------ - - private final Account account; - - // --------------------------- CONSTRUCTORS --------------------------- - - public HomeTimelineTask(Account account) { - this.account = account; - } - - // ------------------------ OVERRIDE METHODS ------------------------ - - @Override - protected List doInBackground() throws TwitterException { - return Tweet.fromTwitter(account.getTwitter().timelines().getHomeTimeline(getPaging()), account.getUserId()); - } - } - - public static class MentionsTimelineTask extends TimelineTask { - - // ------------------------------ FIELDS ------------------------------ - - private final Account account; - - // --------------------------- CONSTRUCTORS --------------------------- - - public MentionsTimelineTask(Account account) { - this.account = account; - } - - // ------------------------ OVERRIDE METHODS ------------------------ - - @Override - protected List doInBackground() throws TwitterException { - return Tweet.fromTwitter(account.getTwitter().timelines().getMentionsTimeline(getPaging()), account.getUserId()); - } - } - - public static class UserTimelineTask extends TimelineTask { - - // ------------------------------ FIELDS ------------------------------ - - private final long userID; - private final Account account; - - // --------------------------- CONSTRUCTORS --------------------------- - - public UserTimelineTask(Account account, long userID) { - this.account = account; - this.userID = userID; - } - - // ------------------------ OVERRIDE METHODS ------------------------ - - @Override - protected List doInBackground() throws TwitterException { - return Tweet.fromTwitter(account.getTwitter().timelines().getUserTimeline(userID, getPaging()), account.getUserId()); - } - } - - public static class UserListStatusesTask extends TimelineTask { - - // ------------------------------ FIELDS ------------------------------ - - private final Account account; - private final String listFullName; - - // --------------------------- CONSTRUCTORS --------------------------- - - public UserListStatusesTask(Account account, String listFullName) { - this.account = account; - this.listFullName = listFullName; - } - - // ------------------------ OVERRIDE METHODS ------------------------ - - @Override - protected List doInBackground() throws TwitterException { - String[] strings = listFullName.split("/"); - return Tweet.fromTwitter(account.getTwitter().list().getUserListStatuses(strings[0], strings[1], getPaging()), account.getUserId()); - } - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/twitter/task/Timelines.kt b/app/src/main/java/net/lacolaco/smileessence/twitter/task/Timelines.kt new file mode 100644 index 00000000..6893319c --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/twitter/task/Timelines.kt @@ -0,0 +1,72 @@ +package net.lacolaco.smileessence.twitter.task + +import net.lacolaco.smileessence.data.Account +import net.lacolaco.smileessence.entity.Tweet +import twitter4j.TwitterException + +class Timelines { + class HomeTimelineTask + // --------------------------- CONSTRUCTORS --------------------------- + + ( + // ------------------------------ FIELDS ------------------------------ + + private val account: Account) : TimelineTask() { + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Throws(TwitterException::class) + override fun doInBackground(): List { + return Tweet.fromTwitter(account.twitter.timelines().getHomeTimeline(paging), account.userId) + } + } + + class MentionsTimelineTask + // --------------------------- CONSTRUCTORS --------------------------- + + ( + // ------------------------------ FIELDS ------------------------------ + + private val account: Account) : TimelineTask() { + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Throws(TwitterException::class) + override fun doInBackground(): List { + return Tweet.fromTwitter(account.twitter.timelines().getMentionsTimeline(paging), account.userId) + } + } + + class UserTimelineTask + // --------------------------- CONSTRUCTORS --------------------------- + + (private val account: Account, + // ------------------------------ FIELDS ------------------------------ + + private val userID: Long) : TimelineTask() { + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Throws(TwitterException::class) + override fun doInBackground(): List { + return Tweet.fromTwitter(account.twitter.timelines().getUserTimeline(userID, paging), account.userId) + } + } + + class UserListStatusesTask + // --------------------------- CONSTRUCTORS --------------------------- + + ( + // ------------------------------ FIELDS ------------------------------ + + private val account: Account, private val listFullName: String) : TimelineTask() { + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Throws(TwitterException::class) + override fun doInBackground(): List { + val strings = listFullName.split("/".toRegex()).dropLastWhile({ it.isEmpty() }).toTypedArray() + return Tweet.fromTwitter(account.twitter.list().getUserListStatuses(strings[0], strings[1], paging), account.userId) + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/twitter/task/TweetReactions.java b/app/src/main/java/net/lacolaco/smileessence/twitter/task/TweetReactions.java deleted file mode 100644 index f201492e..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/twitter/task/TweetReactions.java +++ /dev/null @@ -1,74 +0,0 @@ -package net.lacolaco.smileessence.twitter.task; - -import net.lacolaco.smileessence.data.Account; -import net.lacolaco.smileessence.entity.Tweet; -import net.lacolaco.smileessence.util.BackgroundTask; -import twitter4j.TwitterException; - -public class TweetReactions { - public static class RetweetTask extends BackgroundTask { - - // ------------------------------ FIELDS ------------------------------ - - private final Account account; - private final long statusID; - - // --------------------------- CONSTRUCTORS --------------------------- - - public RetweetTask(Account account, long statusID) { - this.account = account; - this.statusID = statusID; - } - - // ------------------------ OVERRIDE METHODS ------------------------ - - @Override - protected Tweet doInBackground() throws TwitterException { - return Tweet.fromTwitter(account.getTwitter().tweets().retweetStatus(statusID), account.getUserId()); - } - } - - public static class FavoriteTask extends BackgroundTask { - - // ------------------------------ FIELDS ------------------------------ - - private final Account account; - private final long statusID; - - // --------------------------- CONSTRUCTORS --------------------------- - - public FavoriteTask(Account account, long statusID) { - this.account = account; - this.statusID = statusID; - } - - // ------------------------ OVERRIDE METHODS ------------------------ - - @Override - protected Tweet doInBackground() throws TwitterException { - return Tweet.fromTwitter(account.getTwitter().favorites().createFavorite(statusID), account.getUserId()); - } - } - - public static class UnfavoriteTask extends BackgroundTask { - - // ------------------------------ FIELDS ------------------------------ - - private final Account account; - private final long statusID; - - // --------------------------- CONSTRUCTORS --------------------------- - - public UnfavoriteTask(Account account, long statusID) { - this.account = account; - this.statusID = statusID; - } - - // ------------------------ OVERRIDE METHODS ------------------------ - - @Override - protected Tweet doInBackground() throws TwitterException { - return Tweet.fromTwitter(account.getTwitter().favorites().destroyFavorite(statusID), account.getUserId()); - } - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/twitter/task/TweetReactions.kt b/app/src/main/java/net/lacolaco/smileessence/twitter/task/TweetReactions.kt new file mode 100644 index 00000000..bffcd832 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/twitter/task/TweetReactions.kt @@ -0,0 +1,56 @@ +package net.lacolaco.smileessence.twitter.task + +import net.lacolaco.smileessence.data.Account +import net.lacolaco.smileessence.entity.Tweet +import net.lacolaco.smileessence.util.BackgroundTask +import twitter4j.TwitterException + +class TweetReactions { + class RetweetTask + // --------------------------- CONSTRUCTORS --------------------------- + + ( + // ------------------------------ FIELDS ------------------------------ + + private val account: Account, private val statusID: Long) : BackgroundTask() { + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Throws(TwitterException::class) + override fun doInBackground(): Tweet { + return Tweet.fromTwitter(account.twitter.tweets().retweetStatus(statusID), account.userId) + } + } + + class FavoriteTask + // --------------------------- CONSTRUCTORS --------------------------- + + ( + // ------------------------------ FIELDS ------------------------------ + + private val account: Account, private val statusID: Long) : BackgroundTask() { + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Throws(TwitterException::class) + override fun doInBackground(): Tweet { + return Tweet.fromTwitter(account.twitter.favorites().createFavorite(statusID), account.userId) + } + } + + class UnfavoriteTask + // --------------------------- CONSTRUCTORS --------------------------- + + ( + // ------------------------------ FIELDS ------------------------------ + + private val account: Account, private val statusID: Long) : BackgroundTask() { + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Throws(TwitterException::class) + override fun doInBackground(): Tweet { + return Tweet.fromTwitter(account.twitter.favorites().destroyFavorite(statusID), account.userId) + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/twitter/task/Tweets.java b/app/src/main/java/net/lacolaco/smileessence/twitter/task/Tweets.java deleted file mode 100644 index dcad94dc..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/twitter/task/Tweets.java +++ /dev/null @@ -1,153 +0,0 @@ -package net.lacolaco.smileessence.twitter.task; - -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.os.Environment; -import android.text.TextUtils; -import net.lacolaco.smileessence.data.Account; -import net.lacolaco.smileessence.entity.Tweet; -import net.lacolaco.smileessence.logging.Logger; -import net.lacolaco.smileessence.util.BackgroundTask; -import twitter4j.StatusUpdate; -import twitter4j.TwitterException; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -public class Tweets { - public static class GetTask extends BackgroundTask { - private final Account account; - private final long id; - - public GetTask(Account account, long id) { - this.account = account; - this.id = id; - } - - @Override - protected Tweet doInBackground() throws TwitterException { - return Tweet.fromTwitter(account.getTwitter().tweets().showStatus(id), account.getUserId()); - } - } - - public static class CreateTask extends BackgroundTask { - private static final int MEDIA_SIZE_LIMIT = 5 * 1024 * 1024; - private final Account account; - private final StatusUpdate update; - private final String mediaPath; - private String tempFilePath; - private boolean resizeFlag; - - public CreateTask(Account account, StatusUpdate update, String mediaPath, boolean resize) { - this.account = account; - this.update = update; - this.mediaPath = mediaPath; - resizeFlag = resize; - } - - private File getMediaFile() { - File file = new File(mediaPath); - if (file.length() >= MEDIA_SIZE_LIMIT && resizeFlag) { - BitmapFactory.Options opt = new BitmapFactory.Options(); - opt.inJustDecodeBounds = true; //decoder is not return bitmap but set option - BitmapFactory.decodeFile(mediaPath, opt); - tempFilePath = Environment.getExternalStorageDirectory() + "/temp.jpg"; - File compressedFile = new File(tempFilePath); - FileOutputStream fos = null; - try { - fos = new FileOutputStream(compressedFile); - float ratio = (float) file.length() / (float) MEDIA_SIZE_LIMIT; - BitmapFactory.Options resizeOpt = new BitmapFactory.Options(); - resizeOpt.inPurgeable = true; - resizeOpt.inSampleSize = (int) Math.ceil(ratio); - Bitmap bitmap = BitmapFactory.decodeFile(mediaPath, resizeOpt); - bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos); - bitmap.recycle(); - return compressedFile; - } catch (Exception e) { - e.printStackTrace(); - Logger.error(e); - } finally { - try { - if (fos != null) fos.close(); - } catch (IOException e) { - e.printStackTrace(); - Logger.error(e); - } - } - } - return file; - } - - @Override - protected Tweet doInBackground() throws TwitterException { - try { - if (!TextUtils.isEmpty(mediaPath)) { - File mediaFile = getMediaFile(); - if (mediaFile.exists()) { - update.setMedia(mediaFile); - } - } - return Tweet.fromTwitter(account.getTwitter().tweets().updateStatus(update), account.getUserId()); - } finally { - if (tempFilePath != null) { - new File(tempFilePath).delete(); - } - } - } - } - - public static class DestroyTask extends BackgroundTask { - private final Account account; - private final long statusID; - - public DestroyTask(Account account, long statusID) { - this.account = account; - this.statusID = statusID; - } - - @Override - protected Tweet doInBackground() throws TwitterException { - Tweet t = Tweet.fromTwitter(account.getTwitter().tweets().destroyStatus(statusID), account.getUserId()); - // FIXME: Tweet.remove(t.getId()); - return t; - } - } - - public static class GetTalkTask extends BackgroundTask, Tweet> { - private final Account account; - private final long statusId; - - public GetTalkTask(Account account, long statusId) { - this.account = account; - this.statusId = statusId; - } - - @Override - protected List doInBackground() { - ArrayList list = new ArrayList<>(); - long id = statusId; - while (id != -1) { - Tweet tweet = Tweet.fetch(id); - if (tweet == null) { - try { - tweet = Tweet.fromTwitter(account.getTwitter().showStatus(id), account.getUserId()); - } catch (TwitterException ignored) { - } - } - - if (tweet == null) { - break; - } else { - list.add(tweet); - progress(tweet); - id = tweet.getInReplyToStatusId(); - } - } - return list; - } - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/twitter/task/Tweets.kt b/app/src/main/java/net/lacolaco/smileessence/twitter/task/Tweets.kt new file mode 100644 index 00000000..1af42d20 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/twitter/task/Tweets.kt @@ -0,0 +1,125 @@ +package net.lacolaco.smileessence.twitter.task + +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.os.Environment +import android.text.TextUtils +import net.lacolaco.smileessence.data.Account +import net.lacolaco.smileessence.entity.Tweet +import net.lacolaco.smileessence.logging.Logger +import net.lacolaco.smileessence.util.BackgroundTask +import twitter4j.StatusUpdate +import twitter4j.TwitterException + +import java.io.File +import java.io.FileOutputStream +import java.io.IOException +import java.util.ArrayList + +class Tweets { + class GetTask(private val account: Account, private val id: Long) : BackgroundTask() { + + @Throws(TwitterException::class) + override fun doInBackground(): Tweet { + return Tweet.fromTwitter(account.twitter.tweets().showStatus(id), account.userId) + } + } + + class CreateTask(private val account: Account, private val update: StatusUpdate, private val mediaPath: String, private val resizeFlag: Boolean) : BackgroundTask() { + private var tempFilePath: String? = null + + private //decoder is not return bitmap but set option + val mediaFile: File + get() { + val file = File(mediaPath) + if (file.length() >= MEDIA_SIZE_LIMIT && resizeFlag) { + val opt = BitmapFactory.Options() + opt.inJustDecodeBounds = true + BitmapFactory.decodeFile(mediaPath, opt) + tempFilePath = Environment.getExternalStorageDirectory().toString() + "/temp.jpg" + val compressedFile = File(tempFilePath) + var fos: FileOutputStream? = null + try { + fos = FileOutputStream(compressedFile) + val ratio = file.length().toFloat() / MEDIA_SIZE_LIMIT.toFloat() + val resizeOpt = BitmapFactory.Options() + resizeOpt.inPurgeable = true + resizeOpt.inSampleSize = Math.ceil(ratio.toDouble()).toInt() + val bitmap = BitmapFactory.decodeFile(mediaPath, resizeOpt) + bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos) + bitmap.recycle() + return compressedFile + } catch (e: Exception) { + e.printStackTrace() + Logger.error(e) + } finally { + try { + if (fos != null) fos.close() + } catch (e: IOException) { + e.printStackTrace() + Logger.error(e) + } + + } + } + return file + } + + @Throws(TwitterException::class) + override fun doInBackground(): Tweet { + try { + if (!TextUtils.isEmpty(mediaPath)) { + val mediaFile = mediaFile + if (mediaFile.exists()) { + update.setMedia(mediaFile) + } + } + return Tweet.fromTwitter(account.twitter.tweets().updateStatus(update), account.userId) + } finally { + if (tempFilePath != null) { + File(tempFilePath).delete() + } + } + } + + companion object { + private val MEDIA_SIZE_LIMIT = 5 * 1024 * 1024 + } + } + + class DestroyTask(private val account: Account, private val statusID: Long) : BackgroundTask() { + + @Throws(TwitterException::class) + override fun doInBackground(): Tweet { +// FIXME: Tweet.remove(t.getId()); + return Tweet.fromTwitter(account.twitter.tweets().destroyStatus(statusID), account.userId) + } + } + + class GetTalkTask(private val account: Account, private val statusId: Long) : BackgroundTask, Tweet>() { + + override fun doInBackground(): List { + val list = ArrayList() + var id = statusId + while (id != -1L) { + var tweet = Tweet.fetch(id) + if (tweet == null) { + try { + tweet = Tweet.fromTwitter(account.twitter.showStatus(id), account.userId) + } catch (ignored: TwitterException) { + } + + } + + if (tweet == null) { + break + } else { + list.add(tweet) + progress(tweet) + id = tweet.inReplyToStatusId + } + } + return list + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/twitter/task/Users.java b/app/src/main/java/net/lacolaco/smileessence/twitter/task/Users.java deleted file mode 100644 index 60b62841..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/twitter/task/Users.java +++ /dev/null @@ -1,143 +0,0 @@ -package net.lacolaco.smileessence.twitter.task; - -import net.lacolaco.smileessence.data.Account; -import net.lacolaco.smileessence.entity.User; -import net.lacolaco.smileessence.util.BackgroundTask; -import net.lacolaco.smileessence.util.ListUtils; -import twitter4j.Relationship; -import twitter4j.TwitterException; -import twitter4j.UserList; - -import java.util.List; - -public class Users { - public static class GetTask extends BackgroundTask { - private final Account account; - private final long userID; - private final String screenName; - - public GetTask(Account account, long userID) { - this.account = account; - this.userID = userID; - this.screenName = null; - } - - public GetTask(Account account, String screenName) { - this.account = account; - this.screenName = screenName; - this.userID = -1; - } - - @Override - protected User doInBackground() throws TwitterException { - if (screenName != null) { - return User.fromTwitter(account.getTwitter().users().showUser(screenName)); - } else { - return User.fromTwitter(account.getTwitter().users().showUser(userID)); - } - } - } - - public static class GetManyTask extends BackgroundTask, Void> { - private final Account account; - - public GetManyTask(Account account) { - this.account = account; - } - - @Override - protected List doInBackground() throws TwitterException { - return ListUtils.map(account.getTwitter().list().getUserLists(account.getUserId()), UserList::getFullName); - } - } - - public static class FollowTask extends BackgroundTask { - private final Account account; - private final long userID; - - public FollowTask(Account account, long userID) { - this.account = account; - this.userID = userID; - } - - @Override - protected User doInBackground() throws TwitterException { - return User.fromTwitter(account.getTwitter().friendsFollowers().createFriendship(userID)); - } - } - - public static class UnfollowTask extends BackgroundTask { - private final Account account; - private final long userID; - - public UnfollowTask(Account account, long userID) { - this.account = account; - this.userID = userID; - } - - @Override - protected User doInBackground() throws TwitterException { - return User.fromTwitter(account.getTwitter().friendsFollowers().destroyFriendship(userID)); - } - } - - public static class BlockTask extends BackgroundTask { - private final Account account; - private final long userID; - - public BlockTask(Account account, long userID) { - this.account = account; - this.userID = userID; - } - - @Override - protected User doInBackground() throws TwitterException { - return User.fromTwitter(account.getTwitter().users().createBlock(userID)); - } - } - - public static class ReportForSpamTask extends BackgroundTask { - private final Account account; - private final long userID; - - public ReportForSpamTask(Account account, long userID) { - this.account = account; - this.userID = userID; - } - - @Override - protected User doInBackground() throws TwitterException { - return User.fromTwitter(account.getTwitter().spamReporting().reportSpam(userID)); - } - } - - public static class UnblockTask extends BackgroundTask { - private final Account account; - private final long userID; - - public UnblockTask(Account account, long userID) { - this.account = account; - this.userID = userID; - } - - @Override - protected User doInBackground() throws TwitterException { - return User.fromTwitter(account.getTwitter().users().destroyBlock(userID)); - } - } - - public static class ShowFriendshipTask extends BackgroundTask { - private final Account account; - private final long userID; - - public ShowFriendshipTask(Account account, long userID) { - this.account = account; - this.userID = userID; - } - - @Override - protected Relationship doInBackground() throws TwitterException { - return account.getTwitter().friendsFollowers().showFriendship(account.getTwitter().getId(), userID); - } - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/twitter/task/Users.kt b/app/src/main/java/net/lacolaco/smileessence/twitter/task/Users.kt new file mode 100644 index 00000000..c435b560 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/twitter/task/Users.kt @@ -0,0 +1,92 @@ +package net.lacolaco.smileessence.twitter.task + +import net.lacolaco.smileessence.data.Account +import net.lacolaco.smileessence.entity.User +import net.lacolaco.smileessence.util.BackgroundTask +import twitter4j.Relationship +import twitter4j.TwitterException + +class Users { + class GetTask : BackgroundTask { + private val account: Account + private val userID: Long + private val screenName: String? + + constructor(account: Account, userID: Long) { + this.account = account + this.userID = userID + this.screenName = null + } + + constructor(account: Account, screenName: String) { + this.account = account + this.screenName = screenName + this.userID = -1 + } + + @Throws(TwitterException::class) + override fun doInBackground(): User { + return if (screenName != null) { + User.fromTwitter(account.twitter.users().showUser(screenName)) + } else { + User.fromTwitter(account.twitter.users().showUser(userID)) + } + } + } + + class GetManyTask(private val account: Account) : BackgroundTask, Void>() { + + @Throws(TwitterException::class) + override fun doInBackground(): List { + return account.twitter.list().getUserLists(account.userId).map { it.fullName } + } + } + + class FollowTask(private val account: Account, private val userID: Long) : BackgroundTask() { + + @Throws(TwitterException::class) + override fun doInBackground(): User { + return User.fromTwitter(account.twitter.friendsFollowers().createFriendship(userID)) + } + } + + class UnfollowTask(private val account: Account, private val userID: Long) : BackgroundTask() { + + @Throws(TwitterException::class) + override fun doInBackground(): User { + return User.fromTwitter(account.twitter.friendsFollowers().destroyFriendship(userID)) + } + } + + class BlockTask(private val account: Account, private val userID: Long) : BackgroundTask() { + + @Throws(TwitterException::class) + override fun doInBackground(): User { + return User.fromTwitter(account.twitter.users().createBlock(userID)) + } + } + + class ReportForSpamTask(private val account: Account, private val userID: Long) : BackgroundTask() { + + @Throws(TwitterException::class) + override fun doInBackground(): User { + return User.fromTwitter(account.twitter.spamReporting().reportSpam(userID)) + } + } + + class UnblockTask(private val account: Account, private val userID: Long) : BackgroundTask() { + + @Throws(TwitterException::class) + override fun doInBackground(): User { + return User.fromTwitter(account.twitter.users().destroyBlock(userID)) + } + } + + class ShowFriendshipTask(private val account: Account, private val userID: Long) : BackgroundTask() { + + @Throws(TwitterException::class) + override fun doInBackground(): Relationship { + return account.twitter.friendsFollowers().showFriendship(account.twitter.id, userID) + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/util/BackgroundTask.java b/app/src/main/java/net/lacolaco/smileessence/util/BackgroundTask.java deleted file mode 100644 index b6d985e2..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/util/BackgroundTask.java +++ /dev/null @@ -1,111 +0,0 @@ -package net.lacolaco.smileessence.util; - -import android.os.AsyncTask; -import net.lacolaco.smileessence.logging.Logger; - -public abstract class BackgroundTask { - private final InnerAsyncTask task; - private Consumer then; - private Consumer progress; - private Consumer fail; - private Runnable finish; - private Exception exception; - - public BackgroundTask() { - this.task = new InnerAsyncTask(); - } - - public BackgroundTask onDone(Consumer cb) { - this.then = cb; - return this; - } - - public BackgroundTask onProgress(Consumer cb) { - this.progress = cb; - return this; - } - - public BackgroundTask onFail(Consumer cb) { - this.fail = cb; - return this; - } - - public BackgroundTask onFinish(Runnable cb) { - this.finish = cb; - return this; - } - - public BackgroundTask onDoneUI(Consumer cb) { - return onDone(r -> new UIHandler().post(() -> cb.accept(r))); - } - - public BackgroundTask onProgressUI(Consumer cb) { - return onProgress(p -> new UIHandler().post(() -> cb.accept(p))); - } - - public BackgroundTask onFailUI(Consumer cb) { - return onFail(e -> new UIHandler().post(() -> cb.accept(e))); - } - - public BackgroundTask onFinishUI(Runnable cb) { - return onFinish(() -> new UIHandler().post(cb)); - } - - public boolean cancel() { - return task.cancel(true); - } - - public final BackgroundTask execute() { - task.execute(); - return this; - } - - public final Result getImmediately() throws Exception { - Result result = task.get(); - if (exception == null) { - return result; - } else { - throw exception; - } - } - - protected void fail(Exception ex) { - exception = ex; - ex.printStackTrace(); - Logger.error(ex); - - if (!task.isCancelled() && fail != null) { - fail.accept(ex); - } - } - - protected void progress(Progress value) { - if (!task.isCancelled() && exception == null && progress != null) { - progress.accept(value); - } - } - - protected abstract Result doInBackground() throws Exception; - - private class InnerAsyncTask extends AsyncTask { - @Override - protected final void onPostExecute(Result result) { - if (!isCancelled() && exception == null && then != null) { - then.accept(result); - } - if (finish != null) { - finish.run(); - } - } - - @Override - protected Result doInBackground(Void... params) { - try { - return BackgroundTask.this.doInBackground(); - } catch (Exception ex) { - fail(ex); - return null; - } - } - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/util/BackgroundTask.kt b/app/src/main/java/net/lacolaco/smileessence/util/BackgroundTask.kt new file mode 100644 index 00000000..7b9e188a --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/util/BackgroundTask.kt @@ -0,0 +1,113 @@ +package net.lacolaco.smileessence.util + +import android.os.AsyncTask +import net.lacolaco.smileessence.logging.Logger + +abstract class BackgroundTask { + private val task: InnerAsyncTask + private var cbThen: ((Result) -> Unit)? = null + private var cbProgress: ((Progress) -> Unit)? = null + private var cbFail: ((Exception) -> Unit)? = null + private var cbFinish: (() -> Unit)? = null + private var exception: Exception? = null + + init { + this.task = InnerAsyncTask() + } + + fun onDone(cb: (Result) -> Unit): BackgroundTask { + this.cbThen = cb + return this + } + + fun onProgress(cb: (Progress) -> Unit): BackgroundTask { + this.cbProgress = cb + return this + } + + fun onFail(cb: (Exception) -> Unit): BackgroundTask { + this.cbFail = cb + return this + } + + fun onFinish(cb: () -> Unit): BackgroundTask { + this.cbFinish = cb + return this + } + + fun onDoneUI(cb: (Result) -> Unit): BackgroundTask { + return onDone({ r -> UIHandler().post { cb(r) } }) + } + + fun onProgressUI(cb: (Progress) -> Unit): BackgroundTask { + return onProgress({ p -> UIHandler().post { cb(p) } }) + } + + fun onFailUI(cb: (Exception) -> Unit): BackgroundTask { + return onFail({ e -> UIHandler().post { cb(e) } }) + } + + fun onFinishUI(cb: () -> Unit): BackgroundTask { + return onFinish({ UIHandler().post(cb) }) + } + + fun cancel(): Boolean { + return task.cancel(true) + } + + fun execute(): BackgroundTask { + task.execute() + return this + } + + val immediately: Result + @Throws(Exception::class) + get() { + val result = task.get() + return if (exception == null) { + result + } else { + throw exception!! + } + } + + protected fun fail(ex: Exception) { + exception = ex + ex.printStackTrace() + Logger.error(ex) + + if (!task.isCancelled && cbFail != null) { + cbFail!!(ex) + } + } + + protected fun progress(value: Progress) { + if (!task.isCancelled && exception == null && cbProgress != null) { + cbProgress!!(value) + } + } + + @Throws(Exception::class) + protected abstract fun doInBackground(): Result + + private inner class InnerAsyncTask : AsyncTask() { + override fun onPostExecute(result: Result) { + if (!isCancelled && exception == null && cbThen != null) { + cbThen!!(result) + } + if (cbFinish != null) { + cbFinish!!() + } + } + + override fun doInBackground(vararg params: Void): Result? { + try { + return this@BackgroundTask.doInBackground() + } catch (ex: Exception) { + fail(ex) + return null + } + + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/util/BitmapOptimizer.java b/app/src/main/java/net/lacolaco/smileessence/util/BitmapOptimizer.java deleted file mode 100644 index dbb6fccd..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/util/BitmapOptimizer.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.util; - -import android.app.Activity; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Matrix; -import android.media.ExifInterface; -import android.os.Environment; -import net.lacolaco.smileessence.logging.Logger; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -public class BitmapOptimizer { - - // -------------------------- STATIC METHODS -------------------------- - - public static String rotateImageByExif(Activity activity, String filePath) { - filePath = filePath.replace("file://", ""); - int degree = getRotateDegreeFromExif(filePath); - if (degree > 0) { - OutputStream out = null; - Bitmap bitmap = null; - Bitmap rotatedImage = null; - try { - Matrix mat = new Matrix(); - mat.postRotate(degree); - BitmapFactory.Options opt = new BitmapFactory.Options(); - opt.inJustDecodeBounds = true; - BitmapFactory.decodeFile(filePath, opt); - int width = 480; - int scale = 1; - if (opt.outWidth > width) { - scale = opt.outWidth / width + 2; - } - opt.inJustDecodeBounds = false; - opt.inSampleSize = scale; - bitmap = BitmapFactory.decodeFile(filePath, opt); - rotatedImage = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), mat, true); - File file = new File(filePath); - String outPath = activity.getExternalFilesDir(Environment.DIRECTORY_PICTURES) + "/" + file.getName(); - Logger.debug(outPath); - out = new FileOutputStream(outPath); - rotatedImage.compress(Bitmap.CompressFormat.JPEG, 100, out); - return outPath; - } catch (Exception e) { - e.printStackTrace(); - Logger.error(e); - } finally { - if (out != null) { - try { - out.close(); - } catch (IOException e) { - e.printStackTrace(); - Logger.error(e); - } - } - if (bitmap != null) { - bitmap.recycle(); - } - if (rotatedImage != null) { - rotatedImage.recycle(); - } - } - } - return filePath; - } - - private static int getRotateDegreeFromExif(String filePath) { - int degree = 0; - try { - ExifInterface exifInterface = new ExifInterface(filePath); - int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED); - if (orientation == ExifInterface.ORIENTATION_ROTATE_90) { - degree = 90; - } else if (orientation == ExifInterface.ORIENTATION_ROTATE_180) { - degree = 180; - } else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) { - degree = 270; - } - if (degree != 0) { - exifInterface.setAttribute(ExifInterface.TAG_ORIENTATION, "0"); - exifInterface.saveAttributes(); - } - } catch (IOException e) { - degree = -1; - e.printStackTrace(); - Logger.error(e); - } - Logger.debug("Exif degree = " + degree); - return degree; - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/util/BitmapOptimizer.kt b/app/src/main/java/net/lacolaco/smileessence/util/BitmapOptimizer.kt new file mode 100644 index 00000000..b49c9f08 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/util/BitmapOptimizer.kt @@ -0,0 +1,122 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.util + +import android.app.Activity +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Matrix +import android.media.ExifInterface +import android.os.Environment +import net.lacolaco.smileessence.logging.Logger + +import java.io.File +import java.io.FileOutputStream +import java.io.IOException +import java.io.OutputStream + +object BitmapOptimizer { + + // -------------------------- STATIC METHODS -------------------------- + + fun rotateImageByExif(activity: Activity, filePath: String): String { + var filePath = filePath + filePath = filePath.replace("file://", "") + val degree = getRotateDegreeFromExif(filePath) + if (degree > 0) { + var out: OutputStream? = null + var bitmap: Bitmap? = null + var rotatedImage: Bitmap? = null + try { + val mat = Matrix() + mat.postRotate(degree.toFloat()) + val opt = BitmapFactory.Options() + opt.inJustDecodeBounds = true + BitmapFactory.decodeFile(filePath, opt) + val width = 480 + var scale = 1 + if (opt.outWidth > width) { + scale = opt.outWidth / width + 2 + } + opt.inJustDecodeBounds = false + opt.inSampleSize = scale + bitmap = BitmapFactory.decodeFile(filePath, opt) + rotatedImage = Bitmap.createBitmap(bitmap, 0, 0, bitmap!!.width, bitmap.height, mat, true) + val file = File(filePath) + val outPath = activity.getExternalFilesDir(Environment.DIRECTORY_PICTURES).toString() + "/" + file.name + Logger.debug(outPath) + out = FileOutputStream(outPath) + rotatedImage!!.compress(Bitmap.CompressFormat.JPEG, 100, out) + return outPath + } catch (e: Exception) { + e.printStackTrace() + Logger.error(e) + } finally { + if (out != null) { + try { + out.close() + } catch (e: IOException) { + e.printStackTrace() + Logger.error(e) + } + + } + if (bitmap != null) { + bitmap.recycle() + } + if (rotatedImage != null) { + rotatedImage.recycle() + } + } + } + return filePath + } + + private fun getRotateDegreeFromExif(filePath: String): Int { + var degree = 0 + try { + val exifInterface = ExifInterface(filePath) + val orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED) + if (orientation == ExifInterface.ORIENTATION_ROTATE_90) { + degree = 90 + } else if (orientation == ExifInterface.ORIENTATION_ROTATE_180) { + degree = 180 + } else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) { + degree = 270 + } + if (degree != 0) { + exifInterface.setAttribute(ExifInterface.TAG_ORIENTATION, "0") + exifInterface.saveAttributes() + } + } catch (e: IOException) { + degree = -1 + e.printStackTrace() + Logger.error(e) + } + + Logger.debug("Exif degree = " + degree) + return degree + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/util/BitmapThumbnailTask.java b/app/src/main/java/net/lacolaco/smileessence/util/BitmapThumbnailTask.java deleted file mode 100644 index 0aa292cb..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/util/BitmapThumbnailTask.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.util; - -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.media.ThumbnailUtils; -import android.os.AsyncTask; -import android.widget.ImageView; - -public class BitmapThumbnailTask extends AsyncTask { - - // ------------------------------ FIELDS ------------------------------ - - private final String filePath; - private final ImageView imageView; - - // --------------------------- CONSTRUCTORS --------------------------- - - public BitmapThumbnailTask(String filePath, ImageView imageView) { - this.filePath = filePath; - this.imageView = imageView; - } - - // ------------------------ OVERRIDE METHODS ------------------------ - - @Override - protected void onPostExecute(Bitmap bitmap) { - if (bitmap != null && imageView != null) { - imageView.setImageBitmap(bitmap); - } - } - - @Override - protected Bitmap doInBackground(Void... params) { - BitmapFactory.Options opt = new BitmapFactory.Options(); - opt.inPurgeable = true; // GC可能にする - opt.inSampleSize = 2; - // ContentResolver resolver = activity.getContentResolver(); - // Cursor cursor = resolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, MediaStore.Images.ImageColumns.DATA + " = ?", new String[]{filePath}, null); - // if(cursor.moveToFirst()) - // { - // // サムネイルの取得 - // long id = cursor.getLong(cursor.getColumnIndex("_id")); - // return MediaStore.Images.Thumbnails.getThumbnail(resolver, id, MediaStore.Images.Thumbnails.MICRO_KIND, opt); - // } - // return null; - return ThumbnailUtils.extractThumbnail(BitmapFactory.decodeFile(filePath), 100, 100, ThumbnailUtils.OPTIONS_RECYCLE_INPUT); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/util/BitmapThumbnailTask.kt b/app/src/main/java/net/lacolaco/smileessence/util/BitmapThumbnailTask.kt new file mode 100644 index 00000000..6e353716 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/util/BitmapThumbnailTask.kt @@ -0,0 +1,64 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.util + +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.media.ThumbnailUtils +import android.os.AsyncTask +import android.widget.ImageView + +class BitmapThumbnailTask +// --------------------------- CONSTRUCTORS --------------------------- + +( + // ------------------------------ FIELDS ------------------------------ + + private val filePath: String, private val imageView: ImageView?) : AsyncTask() { + + // ------------------------ OVERRIDE METHODS ------------------------ + + override fun onPostExecute(bitmap: Bitmap?) { + if (bitmap != null && imageView != null) { + imageView.setImageBitmap(bitmap) + } + } + + override fun doInBackground(vararg params: Void): Bitmap? { + val opt = BitmapFactory.Options() + opt.inPurgeable = true // GC可能にする + opt.inSampleSize = 2 + // ContentResolver resolver = activity.getContentResolver(); + // Cursor cursor = resolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, MediaStore.Images.ImageColumns.DATA + " = ?", new String[]{filePath}, null); + // if(cursor.moveToFirst()) + // { + // // サムネイルの取得 + // long id = cursor.getLong(cursor.getColumnIndex("_id")); + // return MediaStore.Images.Thumbnails.getThumbnail(resolver, id, MediaStore.Images.Thumbnails.MICRO_KIND, opt); + // } + // return null; + return ThumbnailUtils.extractThumbnail(BitmapFactory.decodeFile(filePath), 100, 100, ThumbnailUtils.OPTIONS_RECYCLE_INPUT) + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/util/BitmapURLTask.java b/app/src/main/java/net/lacolaco/smileessence/util/BitmapURLTask.java deleted file mode 100644 index 151498c3..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/util/BitmapURLTask.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.util; - -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.os.AsyncTask; -import android.widget.ImageView; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; - -public class BitmapURLTask extends AsyncTask { - - // ------------------------------ FIELDS ------------------------------ - - private final String url; - private final ImageView imageView; - - // --------------------------- CONSTRUCTORS --------------------------- - - public BitmapURLTask(String url, ImageView imageView) { - this.url = url; - this.imageView = imageView; - } - - // ------------------------ OVERRIDE METHODS ------------------------ - - @Override - protected void onPostExecute(Bitmap bitmap) { - if (imageView != null) { - imageView.setImageBitmap(bitmap); - } - } - - @Override - protected Bitmap doInBackground(Void... params) { - InputStream inputStream = null; - try { - inputStream = new URL(url).openStream(); - BitmapFactory.Options opt = new BitmapFactory.Options(); - opt.inPurgeable = true; // GC可能にする - return BitmapFactory.decodeStream(inputStream, null, opt); - } catch (IOException e) { - e.printStackTrace(); - return null; - } finally { - if (inputStream != null) { - try { - inputStream.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/util/BitmapURLTask.kt b/app/src/main/java/net/lacolaco/smileessence/util/BitmapURLTask.kt new file mode 100644 index 00000000..f71e4afb --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/util/BitmapURLTask.kt @@ -0,0 +1,68 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.util + +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.os.AsyncTask +import android.widget.ImageView + +import java.io.IOException +import java.io.InputStream +import java.net.URL + +class BitmapURLTask +// --------------------------- CONSTRUCTORS --------------------------- + +( + // ------------------------------ FIELDS ------------------------------ + + private val url: String, private val imageView: ImageView?) : AsyncTask() { + + // ------------------------ OVERRIDE METHODS ------------------------ + + override fun onPostExecute(bitmap: Bitmap) { + imageView?.setImageBitmap(bitmap) + } + + override fun doInBackground(vararg params: Void): Bitmap? { + var inputStream: InputStream? = null + try { + inputStream = URL(url).openStream() + val opt = BitmapFactory.Options() + opt.inPurgeable = true // GC可能にする + return BitmapFactory.decodeStream(inputStream, null, opt) + } catch (e: IOException) { + e.printStackTrace() + return null + } finally { + try { + inputStream?.close() + } catch (e: IOException) { + e.printStackTrace() + } + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/util/Consumer.java b/app/src/main/java/net/lacolaco/smileessence/util/Consumer.java deleted file mode 100644 index a8712293..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/util/Consumer.java +++ /dev/null @@ -1,5 +0,0 @@ -package net.lacolaco.smileessence.util; - -public interface Consumer { - void accept(T t); -} diff --git a/app/src/main/java/net/lacolaco/smileessence/util/Function.java b/app/src/main/java/net/lacolaco/smileessence/util/Function.java deleted file mode 100644 index 5e374e8e..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/util/Function.java +++ /dev/null @@ -1,5 +0,0 @@ -package net.lacolaco.smileessence.util; - -public interface Function { - R apply(T t); -} diff --git a/app/src/main/java/net/lacolaco/smileessence/util/IntentUtils.java b/app/src/main/java/net/lacolaco/smileessence/util/IntentUtils.java deleted file mode 100644 index 9ec4aa46..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/util/IntentUtils.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.util; - -import android.app.Activity; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.net.Uri; -import net.lacolaco.smileessence.Application; -import net.lacolaco.smileessence.R; - -import java.util.List; - -public class IntentUtils { - - // -------------------------- STATIC METHODS -------------------------- - - /** - * Start activity if callable apps are found - * - * @param activity - * @param intent - * @return - */ - public static boolean startActivityIfFound(Activity activity, Intent intent) { - if (canStartActivity(activity, intent)) { - activity.startActivity(intent); - return true; - } else { - Application.toast(R.string.notice_error_start_activity); - } - return false; - } - - /** - * Check intent has any callable activity - * - * @param activity - * @param intent - * @return - */ - public static boolean canStartActivity(Activity activity, Intent intent) { - PackageManager packageManager = activity.getPackageManager(); - List infos = packageManager.queryIntentActivities(intent, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT); - return !infos.isEmpty(); - } - - /** - * Start activity for result if callable apps are found - * - * @param activity - * @param intent - * @param requestCode - * @return - */ - public static boolean startActivityForResultIfFound(Activity activity, Intent intent, int requestCode) { - if (canStartActivity(activity, intent)) { - activity.startActivityForResult(intent, requestCode); - return true; - } else { - Application.toast(R.string.notice_error_start_activity); - } - return false; - } - - public static boolean openUri(Activity activity, String uriString) { - Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uriString)); - return startActivityIfFound(activity, intent); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/util/IntentUtils.kt b/app/src/main/java/net/lacolaco/smileessence/util/IntentUtils.kt new file mode 100644 index 00000000..48b6f9e4 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/util/IntentUtils.kt @@ -0,0 +1,91 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.util + +import android.app.Activity +import android.content.Intent +import android.content.pm.PackageManager +import android.content.pm.ResolveInfo +import android.net.Uri +import net.lacolaco.smileessence.Application +import net.lacolaco.smileessence.R + +object IntentUtils { + + // -------------------------- STATIC METHODS -------------------------- + + /** + * Start activity if callable apps are found + * + * @param activity + * @param intent + * @return + */ + fun startActivityIfFound(activity: Activity, intent: Intent): Boolean { + if (canStartActivity(activity, intent)) { + activity.startActivity(intent) + return true + } else { + Application.toast(R.string.notice_error_start_activity) + } + return false + } + + /** + * Check intent has any callable activity + * + * @param activity + * @param intent + * @return + */ + fun canStartActivity(activity: Activity, intent: Intent): Boolean { + val packageManager = activity.packageManager + val infos = packageManager.queryIntentActivities(intent, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) + return !infos.isEmpty() + } + + /** + * Start activity for result if callable apps are found + * + * @param activity + * @param intent + * @param requestCode + * @return + */ + fun startActivityForResultIfFound(activity: Activity, intent: Intent, requestCode: Int): Boolean { + if (canStartActivity(activity, intent)) { + activity.startActivityForResult(intent, requestCode) + return true + } else { + Application.toast(R.string.notice_error_start_activity) + } + return false + } + + fun openUri(activity: Activity, uriString: String): Boolean { + val intent = Intent(Intent.ACTION_VIEW, Uri.parse(uriString)) + return startActivityIfFound(activity, intent) + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/util/ListUtils.java b/app/src/main/java/net/lacolaco/smileessence/util/ListUtils.java deleted file mode 100644 index 36ade3e6..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/util/ListUtils.java +++ /dev/null @@ -1,24 +0,0 @@ -package net.lacolaco.smileessence.util; - -import java.util.ArrayList; -import java.util.List; - -public class ListUtils { - public static List map(List orig, Function func) { - List result = new ArrayList<>(orig.size()); - for (T item : orig) { - result.add(func.apply(item)); - } - return result; - } - - public static List filter(Iterable orig, Predicate pred) { - List result = new ArrayList<>(); - for (T item : orig) { - if (pred.test(item)) { - result.add(item); - } - } - return result; - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/util/Predicate.java b/app/src/main/java/net/lacolaco/smileessence/util/Predicate.java deleted file mode 100644 index 400310a9..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/util/Predicate.java +++ /dev/null @@ -1,5 +0,0 @@ -package net.lacolaco.smileessence.util; - -public interface Predicate { - boolean test(T t); -} diff --git a/app/src/main/java/net/lacolaco/smileessence/util/StringUtils.java b/app/src/main/java/net/lacolaco/smileessence/util/StringUtils.java deleted file mode 100644 index 07dedb46..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/util/StringUtils.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2015 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.util; - -import android.annotation.SuppressLint; - -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; - -public class StringUtils { - - // -------------------------- STATIC METHODS -------------------------- - - @SuppressLint("SimpleDateFormat") - public static String dateToString(Date date) { - Calendar current = Calendar.getInstance(); - Calendar cal = Calendar.getInstance(); - cal.setTime(date); - - if (isSameYear(current, cal)) { - if (isSameDay(current, cal)) { - return new SimpleDateFormat("HH:mm:ss").format(date); - } else { - return new SimpleDateFormat("MM/dd HH:mm:ss").format(date); - } - } else { - return new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(date); - } - } - - private static boolean isSameDay(Calendar current, Calendar cal) { - return cal.get(Calendar.DAY_OF_YEAR) == current.get(Calendar.DAY_OF_YEAR); - } - - private static boolean isSameYear(Calendar current, Calendar cal) { - return cal.get(Calendar.YEAR) == current.get(Calendar.YEAR); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/util/StringUtils.kt b/app/src/main/java/net/lacolaco/smileessence/util/StringUtils.kt new file mode 100644 index 00000000..cdfe59f5 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/util/StringUtils.kt @@ -0,0 +1,61 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2015 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.util + +import android.annotation.SuppressLint + +import java.text.SimpleDateFormat +import java.util.Calendar +import java.util.Date + +object StringUtils { + + // -------------------------- STATIC METHODS -------------------------- + + @SuppressLint("SimpleDateFormat") + fun dateToString(date: Date): String { + val current = Calendar.getInstance() + val cal = Calendar.getInstance() + cal.time = date + + return if (isSameYear(current, cal)) { + if (isSameDay(current, cal)) { + SimpleDateFormat("HH:mm:ss").format(date) + } else { + SimpleDateFormat("MM/dd HH:mm:ss").format(date) + } + } else { + SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(date) + } + } + + private fun isSameDay(current: Calendar, cal: Calendar): Boolean { + return cal.get(Calendar.DAY_OF_YEAR) == current.get(Calendar.DAY_OF_YEAR) + } + + private fun isSameYear(current: Calendar, cal: Calendar): Boolean { + return cal.get(Calendar.YEAR) == current.get(Calendar.YEAR) + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/util/SystemServiceHelper.java b/app/src/main/java/net/lacolaco/smileessence/util/SystemServiceHelper.java deleted file mode 100644 index 919ef351..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/util/SystemServiceHelper.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.util; - -import android.app.Activity; -import android.content.ClipData; -import android.content.ClipboardManager; -import android.content.Context; -import android.view.View; -import android.view.inputmethod.InputMethodManager; - -public class SystemServiceHelper { - public static void hideIM(Context context, View view) { - if (view != null) { - InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.RESULT_UNCHANGED_SHOWN); - } - } - - public static void showIM(Context context, View view) { - if (view != null) { - InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); - imm.showSoftInput(view, InputMethodManager.RESULT_UNCHANGED_SHOWN); - } - } - - public static void copyToClipboard(Context context, String label, String text) { - ClipboardManager manager = (ClipboardManager) context.getSystemService(Activity.CLIPBOARD_SERVICE); - manager.setPrimaryClip(ClipData.newPlainText(label, text)); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/util/SystemServiceHelper.kt b/app/src/main/java/net/lacolaco/smileessence/util/SystemServiceHelper.kt new file mode 100644 index 00000000..efed67ca --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/util/SystemServiceHelper.kt @@ -0,0 +1,53 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.util + +import android.app.Activity +import android.content.ClipData +import android.content.ClipboardManager +import android.content.Context +import android.view.View +import android.view.inputmethod.InputMethodManager + +object SystemServiceHelper { + fun hideIM(context: Context, view: View?) { + if (view != null) { + val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + imm.hideSoftInputFromWindow(view.windowToken, InputMethodManager.RESULT_UNCHANGED_SHOWN) + } + } + + fun showIM(context: Context, view: View?) { + if (view != null) { + val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + imm.showSoftInput(view, InputMethodManager.RESULT_UNCHANGED_SHOWN) + } + } + + fun copyToClipboard(context: Context, label: String, text: String) { + val manager = context.getSystemService(Activity.CLIPBOARD_SERVICE) as ClipboardManager + manager.primaryClip = ClipData.newPlainText(label, text) + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/util/UIHandler.java b/app/src/main/java/net/lacolaco/smileessence/util/UIHandler.java deleted file mode 100644 index f228f23f..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/util/UIHandler.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.util; - -import android.os.Handler; -import android.os.Looper; - -public class UIHandler extends Handler { - public UIHandler() { - super(Looper.getMainLooper()); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/util/UIHandler.kt b/app/src/main/java/net/lacolaco/smileessence/util/UIHandler.kt new file mode 100644 index 00000000..5c9898a2 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/util/UIHandler.kt @@ -0,0 +1,30 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.util + +import android.os.Handler +import android.os.Looper + +class UIHandler : Handler(Looper.getMainLooper()) diff --git a/app/src/main/java/net/lacolaco/smileessence/util/UIObservable.java b/app/src/main/java/net/lacolaco/smileessence/util/UIObservable.java deleted file mode 100644 index 1cf4efeb..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/util/UIObservable.java +++ /dev/null @@ -1,38 +0,0 @@ -package net.lacolaco.smileessence.util; - -import net.lacolaco.smileessence.entity.RBinding; - -import java.util.*; - -public abstract class UIObservable { - private Map observers = new WeakHashMap<>(); - - public void addObserver(Object weakKey, UIObserver observer) { - synchronized (this) { - observers.put(weakKey, observer); - } - } - - public UIObserver removeObserver(Object weakKey) { - synchronized (this) { - return observers.remove(weakKey); - } - } - - protected void notifyChange(RBinding flag) { - notifyChange(EnumSet.of(flag)); - } - - protected void notifyChange(EnumSet flags) { - List obs = new ArrayList<>(); - synchronized (this) { - obs.addAll(observers.values()); - } - - new UIHandler().post(() -> { - for (UIObserver observer : obs) { - observer.update(flags); - } - }); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/util/UIObservable.kt b/app/src/main/java/net/lacolaco/smileessence/util/UIObservable.kt new file mode 100644 index 00000000..a8f89585 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/util/UIObservable.kt @@ -0,0 +1,38 @@ +package net.lacolaco.smileessence.util + +import net.lacolaco.smileessence.entity.RBinding + +import java.util.* + +abstract class UIObservable { + private val observers = WeakHashMap) -> Unit>() + + fun addObserver(weakKey: Any, observer: (EnumSet) -> Unit) { + synchronized(this) { + observers.put(weakKey, observer) + } + } + + fun removeObserver(weakKey: Any) { + synchronized(this) { + observers.remove(weakKey) + } + } + + protected fun notifyChange(flag: RBinding) { + notifyChange(EnumSet.of(flag)) + } + + protected fun notifyChange(flags: EnumSet) { + val obs = ArrayList<(EnumSet) -> Unit>() + synchronized(this) { + obs.addAll(observers.values) + } + + UIHandler().post { + for (observer in obs) { + observer(flags) + } + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/util/UIObserver.java b/app/src/main/java/net/lacolaco/smileessence/util/UIObserver.java deleted file mode 100644 index 6a621c61..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/util/UIObserver.java +++ /dev/null @@ -1,9 +0,0 @@ -package net.lacolaco.smileessence.util; - -import net.lacolaco.smileessence.entity.RBinding; - -import java.util.EnumSet; - -public interface UIObserver { - void update(EnumSet flags); -} diff --git a/app/src/main/java/net/lacolaco/smileessence/util/UIObserverBundle.java b/app/src/main/java/net/lacolaco/smileessence/util/UIObserverBundle.java deleted file mode 100644 index a1d8957a..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/util/UIObserverBundle.java +++ /dev/null @@ -1,31 +0,0 @@ -package net.lacolaco.smileessence.util; - -import java.util.HashMap; -import java.util.Map; - -// UIObserver と UIObservable のセットを管理するオブジェクトだよ〜〜 -public class UIObserverBundle { - private Map map = new HashMap<>(); - - public void detachAll() { - for (Map.Entry entry : map.entrySet()) { - entry.getKey().removeObserver(this); - } - map.clear(); - } - - public UIObserver attach(UIObservable observable, UIObserver observer) { - observable.addObserver(this, observer); - map.put(observable, observer); - return observer; - } - - @Override - protected void finalize() throws Throwable { - try { - super.finalize(); - } finally { - detachAll(); - } - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/util/UIObserverBundle.kt b/app/src/main/java/net/lacolaco/smileessence/util/UIObserverBundle.kt new file mode 100644 index 00000000..f6c8403b --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/util/UIObserverBundle.kt @@ -0,0 +1,26 @@ +package net.lacolaco.smileessence.util + +import net.lacolaco.smileessence.entity.RBinding +import java.util.* + +// UIObserver と UIObservable のセットを管理するオブジェクトだよ〜〜 +class UIObserverBundle { + private val map = HashMap) -> Unit>() + + fun detachAll() { + for ((key) in map) { + key.removeObserver(this) + } + map.clear() + } + + fun attach(observable: UIObservable, observer: (EnumSet) -> Unit): (EnumSet) -> Unit { + observable.addObserver(this, observer) + map.put(observable, observer) + return observer + } + + protected fun finalize() { + detachAll() + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/ColoredRelativeLayout.java b/app/src/main/java/net/lacolaco/smileessence/view/ColoredRelativeLayout.java deleted file mode 100644 index 33fc05ac..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/ColoredRelativeLayout.java +++ /dev/null @@ -1,61 +0,0 @@ -package net.lacolaco.smileessence.view; - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.util.AttributeSet; -import android.widget.RelativeLayout; -import net.lacolaco.smileessence.R; - - -public class ColoredRelativeLayout extends RelativeLayout { - public static final int HIGHLIGHT_NONE = 0; - private final Paint paint = new Paint(); - private int highlightColors[] = new int[4]; - private boolean showAccent = false; - - public ColoredRelativeLayout(Context context) { - this(context, null); - } - - public ColoredRelativeLayout(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public ColoredRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) { - this(context, attrs, defStyleAttr, 0); - } - - public ColoredRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - - setWillNotDraw(false); - - TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ColoredRelativeLayout); - highlightColors[0] = ta.getColor(R.styleable.ColoredRelativeLayout_highlight_none, R.color.black); - highlightColors[1] = ta.getColor(R.styleable.ColoredRelativeLayout_highlight_type1, R.color.orange); - highlightColors[2] = ta.getColor(R.styleable.ColoredRelativeLayout_highlight_type2, R.color.green); - highlightColors[3] = ta.getColor(R.styleable.ColoredRelativeLayout_highlight_type3, R.color.metro_blue); - setHighlight(HIGHLIGHT_NONE); - paint.setColor(ta.getColor(R.styleable.ColoredRelativeLayout_accent_color, R.color.red)); - paint.setStyle(Paint.Style.STROKE); - paint.setStrokeWidth(3); - ta.recycle(); - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - if (showAccent) - canvas.drawLine(1, 0, 1, getMeasuredHeight(), paint); - } - - public void setAccentVisibility(boolean yes) { - showAccent = yes; - } - - public void setHighlight(int type) { - setBackgroundColor(highlightColors[type]); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/ColoredRelativeLayout.kt b/app/src/main/java/net/lacolaco/smileessence/view/ColoredRelativeLayout.kt new file mode 100644 index 00000000..0bf69378 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/ColoredRelativeLayout.kt @@ -0,0 +1,50 @@ +package net.lacolaco.smileessence.view + +import android.content.Context +import android.content.res.TypedArray +import android.graphics.Canvas +import android.graphics.Paint +import android.util.AttributeSet +import android.widget.RelativeLayout +import net.lacolaco.smileessence.R + + +class ColoredRelativeLayout @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, defStyleRes: Int = 0) : RelativeLayout(context, attrs, defStyleAttr, defStyleRes) { + private val paint = Paint() + private val highlightColors = IntArray(4) + private var showAccent = false + + init { + + setWillNotDraw(false) + + val ta = context.obtainStyledAttributes(attrs, R.styleable.ColoredRelativeLayout) + highlightColors[0] = ta.getColor(R.styleable.ColoredRelativeLayout_highlight_none, R.color.black) + highlightColors[1] = ta.getColor(R.styleable.ColoredRelativeLayout_highlight_type1, R.color.orange) + highlightColors[2] = ta.getColor(R.styleable.ColoredRelativeLayout_highlight_type2, R.color.green) + highlightColors[3] = ta.getColor(R.styleable.ColoredRelativeLayout_highlight_type3, R.color.metro_blue) + setHighlight(HIGHLIGHT_NONE) + paint.color = ta.getColor(R.styleable.ColoredRelativeLayout_accent_color, R.color.red) + paint.style = Paint.Style.STROKE + paint.strokeWidth = 3f + ta.recycle() + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + if (showAccent) + canvas.drawLine(1f, 0f, 1f, measuredHeight.toFloat(), paint) + } + + fun setAccentVisibility(yes: Boolean) { + showAccent = yes + } + + fun setHighlight(type: Int) { + setBackgroundColor(highlightColors[type]) + } + + companion object { + val HIGHLIGHT_NONE = 0 + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/DialogHelper.java b/app/src/main/java/net/lacolaco/smileessence/view/DialogHelper.java deleted file mode 100644 index 3a0003d6..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/DialogHelper.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.view; - -import android.app.Activity; -import net.lacolaco.smileessence.view.dialog.StackableDialogFragment; - -import java.util.ArrayList; -import java.util.LinkedHashSet; -import java.util.Set; -import java.util.UUID; - -/** - * DialogFragment のタグの一覧を保持し「全てのダイアログを閉じる」機能を提供するヘルパークラス - */ -public class DialogHelper { - private static Set dialogStack = new LinkedHashSet<>(); - - public synchronized static void closeAll(Activity activity) { - for (String tag : new ArrayList<>(dialogStack)) { - StackableDialogFragment dialogFragment = (StackableDialogFragment) activity.getFragmentManager().findFragmentByTag(tag); - if (dialogFragment != null) { - dialogFragment.dismiss(); - } - } - } - - public synchronized static int showDialog(Activity activity, StackableDialogFragment dialogFragment) { - String tag = "stackingDialog:" + dialogFragment.getClass().getSimpleName() + ":" + UUID.randomUUID(); - dialogStack.add(tag); - return dialogFragment.show(activity.getFragmentManager().beginTransaction(), tag); - } - - public synchronized static void unregisterDialog(String tag) { - dialogStack.remove(tag); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/DialogHelper.kt b/app/src/main/java/net/lacolaco/smileessence/view/DialogHelper.kt new file mode 100644 index 00000000..c9b4a428 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/DialogHelper.kt @@ -0,0 +1,59 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view + +import android.app.Activity +import net.lacolaco.smileessence.view.dialog.StackableDialogFragment + +import java.util.ArrayList +import java.util.LinkedHashSet +import java.util.UUID + +/** + * DialogFragment のタグの一覧を保持し「全てのダイアログを閉じる」機能を提供するヘルパークラス + */ +object DialogHelper { + private val dialogStack = LinkedHashSet() + + @Synchronized + fun closeAll(activity: Activity) { + for (tag in ArrayList(dialogStack)) { + val dialogFragment = activity.fragmentManager.findFragmentByTag(tag) as StackableDialogFragment? + dialogFragment?.dismiss() + } + } + + @Synchronized + fun showDialog(activity: Activity, dialogFragment: StackableDialogFragment): Int { + val tag = "stackingDialog:" + dialogFragment.javaClass.simpleName + ":" + UUID.randomUUID() + dialogStack.add(tag) + return dialogFragment.show(activity.fragmentManager.beginTransaction(), tag) + } + + @Synchronized + fun unregisterDialog(tag: String) { + dialogStack.remove(tag) + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/ExpandedListView.java b/app/src/main/java/net/lacolaco/smileessence/view/ExpandedListView.java deleted file mode 100644 index e0a4a651..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/ExpandedListView.java +++ /dev/null @@ -1,29 +0,0 @@ -package net.lacolaco.smileessence.view; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.ViewGroup; -import android.widget.ListView; - -public class ExpandedListView extends ListView { - public ExpandedListView(Context context) { - super(context); - } - - public ExpandedListView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public ExpandedListView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - } - - @Override - public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); - super.onMeasure(widthMeasureSpec, expandSpec); - - ViewGroup.LayoutParams params = getLayoutParams(); - params.height = getMeasuredHeight(); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/ExpandedListView.kt b/app/src/main/java/net/lacolaco/smileessence/view/ExpandedListView.kt new file mode 100644 index 00000000..288354ba --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/ExpandedListView.kt @@ -0,0 +1,23 @@ +package net.lacolaco.smileessence.view + +import android.content.Context +import android.util.AttributeSet +import android.view.View +import android.view.ViewGroup +import android.widget.ListView + +class ExpandedListView : ListView { + constructor(context: Context) : super(context) + + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) + + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) + + public override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + val expandSpec = View.MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE shr 2, View.MeasureSpec.AT_MOST) + super.onMeasure(widthMeasureSpec, expandSpec) + + val params = layoutParams + params.height = measuredHeight + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/Partials.java b/app/src/main/java/net/lacolaco/smileessence/view/Partials.java deleted file mode 100644 index fc0e35cb..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/Partials.java +++ /dev/null @@ -1,229 +0,0 @@ -package net.lacolaco.smileessence.view; - -import android.app.Activity; -import android.text.Html; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.ListView; -import android.widget.TextView; -import com.android.volley.toolbox.NetworkImageView; -import net.lacolaco.smileessence.Application; -import net.lacolaco.smileessence.R; -import net.lacolaco.smileessence.activity.MainActivity; -import net.lacolaco.smileessence.data.Account; -import net.lacolaco.smileessence.data.ImageCache; -import net.lacolaco.smileessence.entity.DirectMessage; -import net.lacolaco.smileessence.entity.RBinding; -import net.lacolaco.smileessence.entity.Tweet; -import net.lacolaco.smileessence.preference.UserPreferenceHelper; -import net.lacolaco.smileessence.util.StringUtils; -import net.lacolaco.smileessence.util.UIObserverBundle; -import net.lacolaco.smileessence.view.adapter.CustomListAdapter; -import net.lacolaco.smileessence.view.dialog.MessageDetailDialogFragment; -import net.lacolaco.smileessence.view.dialog.StatusDetailDialogFragment; -import net.lacolaco.smileessence.view.dialog.UserDetailDialogFragment; -import net.lacolaco.smileessence.view.listener.ListItemClickListener; - -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.List; - -public class Partials { - public static View getTweetView(Tweet tweet, Activity activity, View convertView, boolean expandEmbeddedTweets) { - if (convertView == null) { - convertView = activity.getLayoutInflater().inflate(R.layout.list_item_status, null); - } - UIObserverBundle bundle = (UIObserverBundle) convertView.getTag(); - if (bundle != null) { - bundle.detachAll(); - } else { - bundle = new UIObserverBundle(); - convertView.setTag(bundle); - } - - convertView.setOnClickListener(new ListItemClickListener(activity, () -> DialogHelper.showDialog(activity, StatusDetailDialogFragment.newInstance(tweet)))); - - updateViewUser(tweet, activity, convertView); - updateViewBody(tweet, activity, convertView); - updateViewFavorited(tweet, convertView); - updateViewEmbeddeds(tweet, activity, convertView, expandEmbeddedTweets); - - final WeakReference weakView = new WeakReference<>(convertView); - final WeakReference weakActivity = new WeakReference<>(activity); - bundle.attach(tweet.getOriginalTweet(), changes -> { - View strongView = weakView.get(); - if (strongView != null && changes.contains(RBinding.FAVORITERS)) - updateViewFavorited(tweet, strongView); - }); - bundle.attach(tweet.getUser(), changes -> { - View strongView = weakView.get(); - Activity strongActivity = weakActivity.get(); - if (strongView != null && strongActivity != null && changes.contains(RBinding.BASIC)) - updateViewUser(tweet, strongActivity, strongView); - }); - - return convertView; - } - - - private static void updateViewEmbeddeds(Tweet tweet, Activity activity, View convertView, boolean expandEmbeddedTweets) { - final ListView embeddedStatus = (ListView) convertView.findViewById(R.id.listview_status_embedded_status); - if (expandEmbeddedTweets) { - final List list = new ArrayList<>(); - CustomListAdapter embeddedTweetsAdapter = new CustomListAdapter() { - @Override - protected List getList() { - return list; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - return Partials.getTweetView(getItem(position), activity, convertView, false); - } - }; - - Account account = Application.getCurrentWorld().getAccount(); - for (long id : tweet.getEmbeddedStatusIDs()) { - Tweet.fetchTask(id, account).onDone(t -> list.add(t)).execute(); - } - embeddedStatus.setAdapter(embeddedTweetsAdapter); - embeddedStatus.setVisibility(View.VISIBLE); - } else { - embeddedStatus.setAdapter(null); // view may be reused, set null explicitly - embeddedStatus.setVisibility(View.GONE); - } - } - - private static void updateViewUser(Tweet tweet, Activity activity, View convertView) { - int textSize = UserPreferenceHelper.getInstance().getTextSize(); - - NetworkImageView icon = (NetworkImageView) convertView.findViewById(R.id.imageview_status_icon); - String iconUrl = tweet.getOriginalTweet().getUser().getProfileImageUrlOriginal(); - icon.setImageUrl(iconUrl, ImageCache.getImageLoader()); - icon.setOnClickListener(v -> onIconClick(tweet, activity)); - - TextView header = (TextView) convertView.findViewById(R.id.textview_status_header); - header.setTextSize(textSize); - header.setText(tweet.getOriginalTweet().getUser().getFormattedName()); - - ((ColoredRelativeLayout) convertView).setAccentVisibility(tweet.getUser() == Application.getCurrentWorld().getAccount().getUser()); - } - - private static void updateViewBody(Tweet tweet, Activity activity, View convertView) { - int textSize = UserPreferenceHelper.getInstance().getTextSize(); - - TextView content = (TextView) convertView.findViewById(R.id.textview_status_text); - content.setTextSize(textSize); - String rawText = tweet.getOriginalTweet().getText(); - content.setText(rawText); - TextView footer = (TextView) convertView.findViewById(R.id.textview_status_footer); - footer.setTextSize(textSize - 2); - footer.setText(getFooterText(tweet)); - - ColoredRelativeLayout typedView = (ColoredRelativeLayout) convertView; - if (tweet.isRetweet()) { - typedView.setHighlight(2); - } else if (tweet.getOriginalTweet().getMentions().contains(Application.getCurrentWorld().getAccount().getUser().getScreenName())) { - typedView.setHighlight(1); - } else { - typedView.setHighlight(0); - } - } - - private static void updateViewFavorited(Tweet tweet, View convertView) { - ImageView favorited = (ImageView) convertView.findViewById(R.id.imageview_status_favorited); - favorited.setVisibility(tweet.isFavoritedBy(Application.getCurrentWorld().getAccount().getUserId()) ? View.VISIBLE : View.GONE); - } - - private static void onIconClick(Tweet tweet, Activity activity) { - UserDetailDialogFragment dialogFragment = new UserDetailDialogFragment(); - dialogFragment.setUserID(tweet.getOriginalTweet().getUser().getId()); - DialogHelper.showDialog(activity, dialogFragment); - } - - private static String getFooterText(Tweet tweet) { - StringBuilder builder = new StringBuilder(); - if (tweet.isRetweet()) { - builder - .append("(RT: ") - .append(tweet.getUser().getScreenName()) - .append(") "); - } - builder.append(StringUtils.dateToString(tweet.getOriginalTweet().getCreatedAt())); - builder.append(" via "); - builder.append(Html.fromHtml(tweet.getOriginalTweet().getSource())); - return builder.toString(); - } - - public static View getDirectMessageView(DirectMessage directMessage, Activity activity, View convertView) { - if (convertView == null) { - convertView = activity.getLayoutInflater().inflate(R.layout.list_item_status, null); - } - UIObserverBundle bundle = (UIObserverBundle) convertView.getTag(); - if (bundle != null) { - bundle.detachAll(); - } else { - bundle = new UIObserverBundle(); - convertView.setTag(bundle); - } - - convertView.setOnClickListener(new ListItemClickListener(activity, () -> DialogHelper.showDialog(activity, MessageDetailDialogFragment.newInstance(directMessage)))); - - ImageView favorited = (ImageView) convertView.findViewById(R.id.imageview_status_favorited); - favorited.setVisibility(View.GONE); - - updateViewSender(directMessage, activity, convertView); - updateViewBody(directMessage, activity, convertView); - - final WeakReference weakView = new WeakReference<>(convertView); - final WeakReference weakActivity = new WeakReference<>((MainActivity) activity); - bundle.attach(directMessage.getSender(), changes -> { - View strongView = weakView.get(); - MainActivity strongActivity = weakActivity.get(); - if (strongView != null && strongActivity != null && changes.contains(RBinding.BASIC)) - updateViewSender(directMessage, strongActivity, strongView); - }); - - return convertView; - } - - private static String getFooterText(DirectMessage directMessage, Account account) { - StringBuilder builder = new StringBuilder(); - builder.append(StringUtils.dateToString(directMessage.getCreatedAt())); - if (directMessage.getSender().getId() == account.getUserId()) { - builder.append(" to @").append(directMessage.getRecipient().getScreenName()); - } - return builder.toString(); - } - - private static void updateViewSender(DirectMessage directMessage, Activity activity, View convertView) { - int textSize = UserPreferenceHelper.getInstance().getTextSize(); - - NetworkImageView icon = (NetworkImageView) convertView.findViewById(R.id.imageview_status_icon); - String iconUrl = directMessage.getSender().getProfileImageUrlOriginal(); - icon.setImageUrl(iconUrl, ImageCache.getImageLoader()); - icon.setOnClickListener(v -> { - UserDetailDialogFragment dialogFragment = new UserDetailDialogFragment(); - dialogFragment.setUserID(directMessage.getSender().getId()); - DialogHelper.showDialog(activity, dialogFragment); - }); - - TextView header = (TextView) convertView.findViewById(R.id.textview_status_header); - header.setTextSize(textSize); - header.setText(directMessage.getSender().getFormattedName()); - - ((ColoredRelativeLayout) convertView).setAccentVisibility(directMessage.getSender() == Application.getCurrentWorld().getAccount().getUser()); - } - - private static void updateViewBody(DirectMessage directMessage, Activity activity, View convertView) { - int textSize = UserPreferenceHelper.getInstance().getTextSize(); - - TextView content = (TextView) convertView.findViewById(R.id.textview_status_text); - content.setTextSize(textSize); - content.setText(directMessage.getText()); - TextView footer = (TextView) convertView.findViewById(R.id.textview_status_footer); - footer.setTextSize(textSize - 2); - footer.setText(getFooterText(directMessage, Application.getCurrentWorld().getAccount())); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/Partials.kt b/app/src/main/java/net/lacolaco/smileessence/view/Partials.kt new file mode 100644 index 00000000..27d8c3cd --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/Partials.kt @@ -0,0 +1,220 @@ +package net.lacolaco.smileessence.view + +import android.app.Activity +import android.text.Html +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.ListView +import android.widget.TextView +import com.android.volley.toolbox.NetworkImageView +import net.lacolaco.smileessence.Application +import net.lacolaco.smileessence.R +import net.lacolaco.smileessence.activity.MainActivity +import net.lacolaco.smileessence.data.Account +import net.lacolaco.smileessence.data.ImageCache +import net.lacolaco.smileessence.entity.DirectMessage +import net.lacolaco.smileessence.entity.RBinding +import net.lacolaco.smileessence.entity.Tweet +import net.lacolaco.smileessence.preference.UserPreferenceHelper +import net.lacolaco.smileessence.util.StringUtils +import net.lacolaco.smileessence.util.UIObserverBundle +import net.lacolaco.smileessence.view.adapter.CustomListAdapter +import net.lacolaco.smileessence.view.dialog.MessageDetailDialogFragment +import net.lacolaco.smileessence.view.dialog.StatusDetailDialogFragment +import net.lacolaco.smileessence.view.dialog.UserDetailDialogFragment +import net.lacolaco.smileessence.view.listener.ListItemClickListener + +import java.lang.ref.WeakReference +import java.util.ArrayList + +object Partials { + fun getTweetView(tweet: Tweet, activity: Activity, convertView: View?, expandEmbeddedTweets: Boolean): View { + var convertView: View = convertView ?: activity.layoutInflater.inflate(R.layout.list_item_status, null) + var bundle: UIObserverBundle? = convertView.tag as UIObserverBundle? + if (bundle != null) { + bundle.detachAll() + } else { + bundle = UIObserverBundle() + convertView.tag = bundle + } + + convertView.setOnClickListener(ListItemClickListener(activity) { DialogHelper.showDialog(activity, StatusDetailDialogFragment.newInstance(tweet)) }) + + updateViewUser(tweet, activity, convertView) + updateViewBody(tweet, activity, convertView) + updateViewFavorited(tweet, convertView) + updateViewEmbeddeds(tweet, activity, convertView, expandEmbeddedTweets) + + val weakView = WeakReference(convertView) + val weakActivity = WeakReference(activity) + bundle.attach(tweet.originalTweet) { changes -> + val strongView = weakView.get() + if (strongView != null && changes.contains(RBinding.FAVORITERS)) + updateViewFavorited(tweet, strongView) + } + bundle.attach(tweet.user) { changes -> + val strongView = weakView.get() + val strongActivity = weakActivity.get() + if (strongView != null && strongActivity != null && changes.contains(RBinding.BASIC)) + updateViewUser(tweet, strongActivity, strongView) + } + + return convertView + } + + + private fun updateViewEmbeddeds(tweet: Tweet, activity: Activity, convertView: View, expandEmbeddedTweets: Boolean) { + val embeddedStatus = convertView.findViewById(R.id.listview_status_embedded_status) as ListView + if (expandEmbeddedTweets) { + val list = ArrayList() + val embeddedTweetsAdapter = object : CustomListAdapter() { + override val list: List + get() = list + + override fun getView(position: Int, convertView: View, parent: ViewGroup): View { + return Partials.getTweetView(getItem(position), activity, convertView, false) + } + } + + val account = Application.currentWorld!!.account + for (id in tweet.embeddedStatusIDs) { + Tweet.fetchTask(id, account).onDone { t -> list.add(t) }.execute() + } + embeddedStatus.adapter = embeddedTweetsAdapter + embeddedStatus.visibility = View.VISIBLE + } else { + embeddedStatus.adapter = null // view may be reused, set null explicitly + embeddedStatus.visibility = View.GONE + } + } + + private fun updateViewUser(tweet: Tweet, activity: Activity, convertView: View) { + val textSize = UserPreferenceHelper.instance.textSize + + val icon = convertView.findViewById(R.id.imageview_status_icon) as NetworkImageView + val iconUrl = tweet.originalTweet.user.profileImageUrl + icon.setImageUrl(iconUrl, ImageCache.getImageLoader()) + icon.setOnClickListener { v -> onIconClick(tweet, activity) } + + val header = convertView.findViewById(R.id.textview_status_header) as TextView + header.textSize = textSize.toFloat() + header.text = tweet.originalTweet.user.formattedName + + (convertView as ColoredRelativeLayout).setAccentVisibility(tweet.user === Application.currentWorld!!.account.user) + } + + private fun updateViewBody(tweet: Tweet, activity: Activity, convertView: View) { + val textSize = UserPreferenceHelper.instance.textSize + + val content = convertView.findViewById(R.id.textview_status_text) as TextView + content.textSize = textSize.toFloat() + val rawText = tweet.originalTweet.text + content.text = rawText + val footer = convertView.findViewById(R.id.textview_status_footer) as TextView + footer.textSize = (textSize - 2).toFloat() + footer.text = getFooterText(tweet) + + val typedView = convertView as ColoredRelativeLayout + if (tweet.isRetweet) { + typedView.setHighlight(2) + } else if (tweet.originalTweet.mentions.contains(Application.currentWorld!!.account.user.screenName)) { + typedView.setHighlight(1) + } else { + typedView.setHighlight(0) + } + } + + private fun updateViewFavorited(tweet: Tweet, convertView: View) { + val favorited = convertView.findViewById(R.id.imageview_status_favorited) as ImageView + favorited.visibility = if (tweet.isFavoritedBy(Application.currentWorld!!.account.userId)) View.VISIBLE else View.GONE + } + + private fun onIconClick(tweet: Tweet, activity: Activity) { + DialogHelper.showDialog(activity, UserDetailDialogFragment.newInstance(tweet.originalTweet.user)) + } + + private fun getFooterText(tweet: Tweet): String { + val builder = StringBuilder() + if (tweet.isRetweet) { + builder + .append("(RT: ") + .append(tweet.user.screenName) + .append(") ") + } + builder.append(StringUtils.dateToString(tweet.originalTweet.createdAt)) + builder.append(" via ") + builder.append(Html.fromHtml(tweet.originalTweet.source)) + return builder.toString() + } + + fun getDirectMessageView(directMessage: DirectMessage, activity: Activity, convertView: View?): View { + var convertView = convertView + if (convertView == null) { + convertView = activity.layoutInflater.inflate(R.layout.list_item_status, null) + } + var bundle: UIObserverBundle? = convertView!!.tag as UIObserverBundle? + if (bundle != null) { + bundle.detachAll() + } else { + bundle = UIObserverBundle() + convertView.tag = bundle + } + + convertView.setOnClickListener(ListItemClickListener(activity) { DialogHelper.showDialog(activity, MessageDetailDialogFragment.newInstance(directMessage)) }) + + val favorited = convertView.findViewById(R.id.imageview_status_favorited) as ImageView + favorited.visibility = View.GONE + + updateViewSender(directMessage, activity, convertView) + updateViewBody(directMessage, activity, convertView) + + val weakView = WeakReference(convertView) + val weakActivity = WeakReference(activity as MainActivity) + bundle.attach(directMessage.sender) { changes -> + val strongView = weakView.get() + val strongActivity = weakActivity.get() + if (strongView != null && strongActivity != null && changes.contains(RBinding.BASIC)) + updateViewSender(directMessage, strongActivity, strongView) + } + + return convertView + } + + private fun getFooterText(directMessage: DirectMessage, account: Account): String { + val builder = StringBuilder() + builder.append(StringUtils.dateToString(directMessage.createdAt)) + if (directMessage.sender.id == account.userId) { + builder.append(" to @").append(directMessage.recipient.screenName) + } + return builder.toString() + } + + private fun updateViewSender(directMessage: DirectMessage, activity: Activity, convertView: View) { + val textSize = UserPreferenceHelper.instance.textSize + + val icon = convertView.findViewById(R.id.imageview_status_icon) as NetworkImageView + val iconUrl = directMessage.sender.profileImageUrl + icon.setImageUrl(iconUrl, ImageCache.getImageLoader()) + icon.setOnClickListener { v -> + DialogHelper.showDialog(activity, UserDetailDialogFragment.newInstance(directMessage.sender)) + } + + val header = convertView.findViewById(R.id.textview_status_header) as TextView + header.textSize = textSize.toFloat() + header.text = directMessage.sender.formattedName + + (convertView as ColoredRelativeLayout).setAccentVisibility(directMessage.sender === Application.currentWorld!!.account.user) + } + + private fun updateViewBody(directMessage: DirectMessage, activity: Activity, convertView: View) { + val textSize = UserPreferenceHelper.instance.textSize + + val content = convertView.findViewById(R.id.textview_status_text) as TextView + content.textSize = textSize.toFloat() + content.text = directMessage.text + val footer = convertView.findViewById(R.id.textview_status_footer) as TextView + footer.textSize = (textSize - 2).toFloat() + footer.text = getFooterText(directMessage, Application.currentWorld!!.account) + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/SettingFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/SettingFragment.java deleted file mode 100644 index 7ed9636b..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/SettingFragment.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.view; - -import android.app.AlertDialog; -import android.content.Intent; -import android.content.SharedPreferences; -import android.os.Bundle; -import android.preference.EditTextPreference; -import android.preference.ListPreference; -import android.preference.Preference; -import android.preference.PreferenceFragment; -import android.text.TextUtils; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.TextView; -import net.lacolaco.smileessence.Application; -import net.lacolaco.smileessence.BuildConfig; -import net.lacolaco.smileessence.R; -import net.lacolaco.smileessence.activity.LicenseActivity; - -import static android.content.SharedPreferences.OnSharedPreferenceChangeListener; - -public class SettingFragment extends PreferenceFragment implements OnSharedPreferenceChangeListener, - Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener { - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - String newValueStr = String.valueOf(newValue); - if (preference.getKey().contentEquals(getString(R.string.key_setting_text_size))) { - if (TextUtils.isDigitsOnly(newValueStr)) { - return true; - } else { - Application.toast(R.string.error_setting_text_size_not_number); - } - return false; - } else if (preference.getKey().contentEquals(getString(R.string.key_setting_theme))) { - Application.toast(R.string.notice_theme_changed); - } - return true; - } - - // --------------------- Interface OnPreferenceClickListener --------------------- - - @Override - public boolean onPreferenceClick(Preference preference) { - String key = preference.getKey(); - if (key.contentEquals(getString(R.string.key_setting_application_information))) { - openAppInfoDialog(); - } else if (key.contentEquals(getString(R.string.key_setting_licenses))) { - openLicenseActivity(); - } - return true; - } - - // --------------------- Interface OnSharedPreferenceChangeListener --------------------- - - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - setSummaryCurrentValue(); - } - - // ------------------------ OVERRIDE METHODS ------------------------ - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.setting); - EditTextPreference textSizePreference = (EditTextPreference) findPreference(R.string.key_setting_text_size); - textSizePreference.setSummary(textSizePreference.getText()); - textSizePreference.setOnPreferenceChangeListener(this); - ListPreference themePreference = (ListPreference) findPreference(R.string.key_setting_theme); - themePreference.setSummary(themePreference.getEntry()); - themePreference.setOnPreferenceChangeListener(this); - Preference appInfoPreference = findPreference(R.string.key_setting_application_information); - appInfoPreference.setOnPreferenceClickListener(this); - appInfoPreference.setSummary(BuildConfig.VERSION_NAME + " (" + BuildConfig.VERSION_CODE + ")"); - Preference license = findPreference(R.string.key_setting_licenses); - license.setOnPreferenceClickListener(this); - } - - @Override - public void onPause() { - super.onPause(); - SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences(); - sharedPreferences.unregisterOnSharedPreferenceChangeListener(this); - } - - @Override - public void onResume() { - super.onResume(); - SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences(); - sharedPreferences.registerOnSharedPreferenceChangeListener(this); - } - - // -------------------------- OTHER METHODS -------------------------- - - public Preference findPreference(int preferenceResID) { - return findPreference(getString(preferenceResID)); - } - - private void openLicenseActivity() { - Intent intent = new Intent(getActivity(), LicenseActivity.class); - getActivity().startActivity(intent); - } - - private void openAppInfoDialog() { - LayoutInflater inflater = getActivity().getLayoutInflater(); - View contentView = inflater.inflate(R.layout.dialog_app_info, null); - TextView versionTextView = (TextView) contentView.findViewById(R.id.versionTextView); - versionTextView.setText(BuildConfig.VERSION_NAME + " (rev: " + BuildConfig.VERSION_CODE + "; upstream: " + getString(R.string.app_version_full) + ")"); - - new AlertDialog.Builder(getActivity()) - .setTitle(R.string.dialog_title_about) - .setView(contentView) - .setPositiveButton(R.string.alert_dialog_ok, (dialog, which) -> dialog.dismiss()) - .create().show(); - } - - private void setSummaryCurrentValue() { - EditTextPreference textSizePreference = (EditTextPreference) findPreference(R.string.key_setting_text_size); - textSizePreference.setSummary(textSizePreference.getText()); - ListPreference themePreference = (ListPreference) findPreference(R.string.key_setting_theme); - themePreference.setSummary(themePreference.getEntry()); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/SettingFragment.kt b/app/src/main/java/net/lacolaco/smileessence/view/SettingFragment.kt new file mode 100644 index 00000000..05490f97 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/SettingFragment.kt @@ -0,0 +1,140 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view + +import android.app.AlertDialog +import android.content.Intent +import android.content.SharedPreferences +import android.os.Bundle +import android.preference.EditTextPreference +import android.preference.ListPreference +import android.preference.Preference +import android.preference.PreferenceFragment +import android.text.TextUtils +import android.view.LayoutInflater +import android.view.View +import android.widget.TextView +import net.lacolaco.smileessence.Application +import net.lacolaco.smileessence.BuildConfig +import net.lacolaco.smileessence.R +import net.lacolaco.smileessence.activity.LicenseActivity + +import android.content.SharedPreferences.OnSharedPreferenceChangeListener + +class SettingFragment : PreferenceFragment(), OnSharedPreferenceChangeListener, Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener { + override fun onPreferenceChange(preference: Preference, newValue: Any): Boolean { + val newValueStr = newValue.toString() + if (preference.key.contentEquals(getString(R.string.key_setting_text_size))) { + if (TextUtils.isDigitsOnly(newValueStr)) { + return true + } else { + Application.toast(R.string.error_setting_text_size_not_number) + } + return false + } else if (preference.key.contentEquals(getString(R.string.key_setting_theme))) { + Application.toast(R.string.notice_theme_changed) + } + return true + } + + // --------------------- Interface OnPreferenceClickListener --------------------- + + override fun onPreferenceClick(preference: Preference): Boolean { + val key = preference.key + if (key.contentEquals(getString(R.string.key_setting_application_information))) { + openAppInfoDialog() + } else if (key.contentEquals(getString(R.string.key_setting_licenses))) { + openLicenseActivity() + } + return true + } + + // --------------------- Interface OnSharedPreferenceChangeListener --------------------- + + override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) { + setSummaryCurrentValue() + } + + // ------------------------ OVERRIDE METHODS ------------------------ + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + addPreferencesFromResource(R.xml.setting) + val textSizePreference = findPreference(R.string.key_setting_text_size) as EditTextPreference + textSizePreference.summary = textSizePreference.text + textSizePreference.onPreferenceChangeListener = this + val themePreference = findPreference(R.string.key_setting_theme) as ListPreference + themePreference.summary = themePreference.entry + themePreference.onPreferenceChangeListener = this + val appInfoPreference = findPreference(R.string.key_setting_application_information) + appInfoPreference.onPreferenceClickListener = this + appInfoPreference.summary = BuildConfig.VERSION_NAME + " (" + BuildConfig.VERSION_CODE + ")" + val license = findPreference(R.string.key_setting_licenses) + license.onPreferenceClickListener = this + } + + override fun onPause() { + super.onPause() + val sharedPreferences = preferenceScreen.sharedPreferences + sharedPreferences.unregisterOnSharedPreferenceChangeListener(this) + } + + override fun onResume() { + super.onResume() + val sharedPreferences = preferenceScreen.sharedPreferences + sharedPreferences.registerOnSharedPreferenceChangeListener(this) + } + + // -------------------------- OTHER METHODS -------------------------- + + fun findPreference(preferenceResID: Int): Preference { + return findPreference(getString(preferenceResID)) + } + + private fun openLicenseActivity() { + val intent = Intent(activity, LicenseActivity::class.java) + activity.startActivity(intent) + } + + private fun openAppInfoDialog() { + val inflater = activity.layoutInflater + val contentView = inflater.inflate(R.layout.dialog_app_info, null) + val versionTextView = contentView.findViewById(R.id.versionTextView) as TextView + versionTextView.text = BuildConfig.VERSION_NAME + " (rev: " + BuildConfig.VERSION_CODE + "; upstream: " + getString(R.string.app_version_full) + ")" + + AlertDialog.Builder(activity) + .setTitle(R.string.dialog_title_about) + .setView(contentView) + .setPositiveButton(R.string.alert_dialog_ok) { dialog, which -> dialog.dismiss() } + .create().show() + } + + private fun setSummaryCurrentValue() { + val textSizePreference = findPreference(R.string.key_setting_text_size) as EditTextPreference + textSizePreference.summary = textSizePreference.text + val themePreference = findPreference(R.string.key_setting_theme) as ListPreference + themePreference.summary = themePreference.entry + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/ThreeStateButton.java b/app/src/main/java/net/lacolaco/smileessence/view/ThreeStateButton.java deleted file mode 100644 index d5358db5..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/ThreeStateButton.java +++ /dev/null @@ -1,56 +0,0 @@ -package net.lacolaco.smileessence.view; - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.drawable.Drawable; -import android.util.AttributeSet; -import android.widget.Button; -import net.lacolaco.smileessence.R; - -public class ThreeStateButton extends Button { - public static final int STATE_OFF = 0; - public static final int STATE_ON = 1; - public static final int STATE_LOCKED = 2; - - private int state = STATE_OFF; - private String texts[] = new String[3]; - private Drawable backgrounds[] = new Drawable[3]; - - public ThreeStateButton(Context context) { - this(context, null); - } - - public ThreeStateButton(Context context, AttributeSet attrs) { - this(context, attrs, android.R.attr.buttonStyle); - } - - public ThreeStateButton(Context context, AttributeSet attrs, int defStyleAttr) { - this(context, attrs, defStyleAttr, 0); - } - - public ThreeStateButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - - TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ThreeStateButton); - texts[STATE_OFF] = ta.getString(R.styleable.ThreeStateButton_off_text); - texts[STATE_ON] = ta.getString(R.styleable.ThreeStateButton_on_text); - texts[STATE_LOCKED] = ta.getString(R.styleable.ThreeStateButton_locked_text); - backgrounds[STATE_OFF] = ta.getDrawable(R.styleable.ThreeStateButton_off_background); - backgrounds[STATE_ON] = ta.getDrawable(R.styleable.ThreeStateButton_on_background); - backgrounds[STATE_LOCKED] = ta.getDrawable(R.styleable.ThreeStateButton_locked_background); - ta.recycle(); - - setState(STATE_OFF); - } - - public int getState() { - return state; - } - - public void setState(int s) { - state = s; - setText(texts[state]); - setBackground(backgrounds[state]); - setEnabled(state != STATE_LOCKED); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/ThreeStateButton.kt b/app/src/main/java/net/lacolaco/smileessence/view/ThreeStateButton.kt new file mode 100644 index 00000000..547aa84d --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/ThreeStateButton.kt @@ -0,0 +1,41 @@ +package net.lacolaco.smileessence.view + +import android.content.Context +import android.content.res.TypedArray +import android.graphics.drawable.Drawable +import android.util.AttributeSet +import android.widget.Button +import net.lacolaco.smileessence.R + +class ThreeStateButton @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = android.R.attr.buttonStyle, defStyleRes: Int = 0) : Button(context, attrs, defStyleAttr, defStyleRes) { + + var state = STATE_OFF + set(s) { + field = s + text = texts[this.state] + background = backgrounds[this.state] + isEnabled = this.state != STATE_LOCKED + } + private val texts = arrayOfNulls(3) + private val backgrounds = arrayOfNulls(3) + + init { + + val ta = context.obtainStyledAttributes(attrs, R.styleable.ThreeStateButton) + texts[STATE_OFF] = ta.getString(R.styleable.ThreeStateButton_off_text) + texts[STATE_ON] = ta.getString(R.styleable.ThreeStateButton_on_text) + texts[STATE_LOCKED] = ta.getString(R.styleable.ThreeStateButton_locked_text) + backgrounds[STATE_OFF] = ta.getDrawable(R.styleable.ThreeStateButton_off_background) + backgrounds[STATE_ON] = ta.getDrawable(R.styleable.ThreeStateButton_on_background) + backgrounds[STATE_LOCKED] = ta.getDrawable(R.styleable.ThreeStateButton_locked_background) + ta.recycle() + + state = STATE_OFF + } + + companion object { + val STATE_OFF = 0 + val STATE_ON = 1 + val STATE_LOCKED = 2 + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/ToggleableImageButton.java b/app/src/main/java/net/lacolaco/smileessence/view/ToggleableImageButton.java deleted file mode 100644 index b7b2d174..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/ToggleableImageButton.java +++ /dev/null @@ -1,37 +0,0 @@ -package net.lacolaco.smileessence.view; - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.drawable.Drawable; -import android.util.AttributeSet; -import android.widget.ImageButton; -import net.lacolaco.smileessence.R; - -public class ToggleableImageButton extends ImageButton { - private Drawable onSrc, offSrc; - - public ToggleableImageButton(Context context) { - this(context, null); - } - - public ToggleableImageButton(Context context, AttributeSet attrs) { - this(context, attrs, android.R.attr.imageButtonStyle); - } - - public ToggleableImageButton(Context context, AttributeSet attrs, int defStyleAttr) { - this(context, attrs, defStyleAttr, 0); - } - - public ToggleableImageButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - - TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ToggleableImageButton); - offSrc = ta.getDrawable(R.styleable.ToggleableImageButton_offSrc); - onSrc = ta.getDrawable(R.styleable.ToggleableImageButton_onSrc); - ta.recycle(); - } - - public void setState(boolean isOn) { - setImageDrawable(isOn ? onSrc : offSrc); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/ToggleableImageButton.kt b/app/src/main/java/net/lacolaco/smileessence/view/ToggleableImageButton.kt new file mode 100644 index 00000000..47a1821a --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/ToggleableImageButton.kt @@ -0,0 +1,25 @@ +package net.lacolaco.smileessence.view + +import android.content.Context +import android.content.res.TypedArray +import android.graphics.drawable.Drawable +import android.util.AttributeSet +import android.widget.ImageButton +import net.lacolaco.smileessence.R + +class ToggleableImageButton @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = android.R.attr.imageButtonStyle, defStyleRes: Int = 0) : ImageButton(context, attrs, defStyleAttr, defStyleRes) { + private val onSrc: Drawable + private val offSrc: Drawable + + init { + + val ta = context.obtainStyledAttributes(attrs, R.styleable.ToggleableImageButton) + offSrc = ta.getDrawable(R.styleable.ToggleableImageButton_offSrc) + onSrc = ta.getDrawable(R.styleable.ToggleableImageButton_onSrc) + ta.recycle() + } + + fun setState(isOn: Boolean) { + setImageDrawable(if (isOn) onSrc else offSrc) + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/adapter/CustomListAdapter.java b/app/src/main/java/net/lacolaco/smileessence/view/adapter/CustomListAdapter.java deleted file mode 100644 index 6d7420fb..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/adapter/CustomListAdapter.java +++ /dev/null @@ -1,50 +0,0 @@ -package net.lacolaco.smileessence.view.adapter; - -import android.widget.BaseAdapter; -import net.lacolaco.smileessence.util.UIHandler; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -public abstract class CustomListAdapter extends BaseAdapter { - private boolean isNotifiable = true; - private List frozenList = new ArrayList<>(); - - public final void setNotifiable(boolean notifiable) { - isNotifiable = notifiable; - } - - @Override - public final int getCount() { - return frozenList.size(); - } - - @Override - public final T getItem(int position) { - return frozenList.get(position); - } - - @Override - public long getItemId(int position) { - return position; - } - - @Override - public final void notifyDataSetChanged() { - frozenList = Collections.unmodifiableList(getList()); - super.notifyDataSetChanged(); - } - - protected abstract List getList(); - - public void update() { - if (isNotifiable) { - updateForce(); - } - } - - public void updateForce() { - new UIHandler().post(this::notifyDataSetChanged); - } -} \ No newline at end of file diff --git a/app/src/main/java/net/lacolaco/smileessence/view/adapter/CustomListAdapter.kt b/app/src/main/java/net/lacolaco/smileessence/view/adapter/CustomListAdapter.kt new file mode 100644 index 00000000..3b022012 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/adapter/CustomListAdapter.kt @@ -0,0 +1,45 @@ +package net.lacolaco.smileessence.view.adapter + +import android.widget.BaseAdapter +import net.lacolaco.smileessence.util.UIHandler + +import java.util.ArrayList +import java.util.Collections + +abstract class CustomListAdapter : BaseAdapter() { + private var isNotifiable = true + private var frozenList: List = ArrayList() + + fun setNotifiable(notifiable: Boolean) { + isNotifiable = notifiable + } + + override fun getCount(): Int { + return frozenList.size + } + + override fun getItem(position: Int): T { + return frozenList[position] + } + + override fun getItemId(position: Int): Long { + return position.toLong() + } + + override fun notifyDataSetChanged() { + frozenList = Collections.unmodifiableList(list) + super.notifyDataSetChanged() + } + + protected abstract val list: List + + fun update() { + if (isNotifiable) { + updateForce() + } + } + + fun updateForce() { + UIHandler().post { this.notifyDataSetChanged() } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/lacolaco/smileessence/view/adapter/EventListAdapter.java b/app/src/main/java/net/lacolaco/smileessence/view/adapter/EventListAdapter.java deleted file mode 100644 index 3f98cfaa..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/adapter/EventListAdapter.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.view.adapter; - -import android.app.Activity; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; -import com.android.volley.toolbox.NetworkImageView; -import net.lacolaco.smileessence.R; -import net.lacolaco.smileessence.World; -import net.lacolaco.smileessence.data.ImageCache; -import net.lacolaco.smileessence.entity.Event; -import net.lacolaco.smileessence.entity.RBinding; -import net.lacolaco.smileessence.preference.UserPreferenceHelper; -import net.lacolaco.smileessence.util.StringUtils; -import net.lacolaco.smileessence.util.UIObserverBundle; -import net.lacolaco.smileessence.view.DialogHelper; -import net.lacolaco.smileessence.view.dialog.UserDetailDialogFragment; -import net.lacolaco.smileessence.view.listener.ListItemClickListener; - -import java.lang.ref.WeakReference; -import java.util.List; - -public class EventListAdapter extends CustomListAdapter { - private final World world; - private final Activity activity; - - public EventListAdapter(World world, Activity activity) { - super(); - this.world = world; - this.activity = activity; - } - - @Override - protected List getList() { - return world.getEvents(); - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - Event event = getItem(position); - if (convertView == null) { - convertView = activity.getLayoutInflater().inflate(R.layout.list_item_status, null); - } - UIObserverBundle bundle = (UIObserverBundle) convertView.getTag(); - if (bundle != null) { - bundle.detachAll(); - } else { - bundle = new UIObserverBundle(); - convertView.setTag(bundle); - } - - int textSize = UserPreferenceHelper.getInstance().getTextSize(); - - TextView header = (TextView) convertView.findViewById(R.id.textview_status_header); - header.setTextSize(textSize); - - updateViewUser(event, convertView); - - TextView content = (TextView) convertView.findViewById(R.id.textview_status_text); - content.setTextSize(textSize); - content.setText(event.getTargetObject() != null ? event.getTargetObject().getText() : ""); - TextView footer = (TextView) convertView.findViewById(R.id.textview_status_footer); - footer.setTextSize(textSize - 2); - footer.setText(StringUtils.dateToString(event.getCreatedAt())); - ImageView favorited = (ImageView) convertView.findViewById(R.id.imageview_status_favorited); - favorited.setVisibility(View.GONE); - convertView.setOnClickListener(new ListItemClickListener(activity, () -> { - UserDetailDialogFragment fragment = new UserDetailDialogFragment(); - fragment.setUserID(event.getSource().getId()); - DialogHelper.showDialog(activity, fragment); - })); - - final WeakReference weakView = new WeakReference<>(convertView); - bundle.attach(event.getSource(), changes -> { - View strongView = weakView.get(); - if (strongView != null && changes.contains(RBinding.BASIC)) - updateViewUser(event, strongView); - }); - - return convertView; - } - - private void updateViewUser(Event event, View convertedView) { - NetworkImageView icon = (NetworkImageView) convertedView.findViewById(R.id.imageview_status_icon); - String iconUrl = event.getSource().getProfileImageUrlOriginal(); - icon.setImageUrl(iconUrl, ImageCache.getImageLoader()); - - TextView header = (TextView) convertedView.findViewById(R.id.textview_status_header); - header.setText(event.getFormattedString()); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/adapter/EventListAdapter.kt b/app/src/main/java/net/lacolaco/smileessence/view/adapter/EventListAdapter.kt new file mode 100644 index 00000000..1c19d4ec --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/adapter/EventListAdapter.kt @@ -0,0 +1,102 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.adapter + +import android.app.Activity +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import com.android.volley.toolbox.NetworkImageView +import net.lacolaco.smileessence.R +import net.lacolaco.smileessence.World +import net.lacolaco.smileessence.data.ImageCache +import net.lacolaco.smileessence.entity.Event +import net.lacolaco.smileessence.entity.RBinding +import net.lacolaco.smileessence.preference.UserPreferenceHelper +import net.lacolaco.smileessence.util.StringUtils +import net.lacolaco.smileessence.util.UIObserverBundle +import net.lacolaco.smileessence.view.DialogHelper +import net.lacolaco.smileessence.view.dialog.UserDetailDialogFragment +import net.lacolaco.smileessence.view.listener.ListItemClickListener + +import java.lang.ref.WeakReference + +class EventListAdapter(private val world: World, private val activity: Activity) : CustomListAdapter() { + override val list: List + get() = world.events + + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { + var convertView = convertView + val event = getItem(position) + if (convertView == null) { + convertView = activity.layoutInflater.inflate(R.layout.list_item_status, null) + } + var bundle: UIObserverBundle? = convertView!!.tag as UIObserverBundle? + if (bundle != null) { + bundle.detachAll() + } else { + bundle = UIObserverBundle() + convertView.tag = bundle + } + + val textSize = UserPreferenceHelper.instance.textSize + + val header = convertView.findViewById(R.id.textview_status_header) as TextView + header.textSize = textSize.toFloat() + + updateViewUser(event, convertView) + + val content = convertView.findViewById(R.id.textview_status_text) as TextView + content.textSize = textSize.toFloat() + content.text = event.targetObject?.text ?: "" + val footer = convertView.findViewById(R.id.textview_status_footer) as TextView + footer.textSize = (textSize - 2).toFloat() + footer.text = StringUtils.dateToString(event.createdAt) + val favorited = convertView.findViewById(R.id.imageview_status_favorited) as ImageView + favorited.visibility = View.GONE + convertView.setOnClickListener(ListItemClickListener(activity) { + DialogHelper.showDialog(activity, UserDetailDialogFragment.newInstance(event.source)) + }) + + val weakView = WeakReference(convertView) + bundle.attach(event.source) { changes -> + val strongView = weakView.get() + if (strongView != null && changes.contains(RBinding.BASIC)) + updateViewUser(event, strongView) + } + + return convertView + } + + private fun updateViewUser(event: Event, convertedView: View) { + val icon = convertedView.findViewById(R.id.imageview_status_icon) as NetworkImageView + val iconUrl = event.source.profileImageUrl + icon.setImageUrl(iconUrl, ImageCache.getImageLoader()) + + val header = convertedView.findViewById(R.id.textview_status_header) as TextView + header.text = event.formattedString + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/adapter/MessageListAdapter.java b/app/src/main/java/net/lacolaco/smileessence/view/adapter/MessageListAdapter.java deleted file mode 100644 index 9f8e5039..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/adapter/MessageListAdapter.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.view.adapter; - -import android.app.Activity; -import android.view.View; -import android.view.ViewGroup; -import net.lacolaco.smileessence.entity.DirectMessage; -import net.lacolaco.smileessence.view.Partials; - -public class MessageListAdapter extends OrderedCustomListAdapter { - private final Activity activity; - - public MessageListAdapter(Activity activity) { - super(); - this.activity = activity; - } - - public long getLastID() { - return getCount() > 0 ? getItem(getCount() - 1).getId() : -1; - } - - public long getTopID() { - return getCount() > 0 ? getItem(0).getId() : -1; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - return Partials.getDirectMessageView(getItem(position), activity, convertView); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/adapter/MessageListAdapter.kt b/app/src/main/java/net/lacolaco/smileessence/view/adapter/MessageListAdapter.kt new file mode 100644 index 00000000..d72ab564 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/adapter/MessageListAdapter.kt @@ -0,0 +1,43 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.adapter + +import android.app.Activity +import android.view.View +import android.view.ViewGroup +import net.lacolaco.smileessence.entity.DirectMessage +import net.lacolaco.smileessence.view.Partials + +class MessageListAdapter(private val activity: Activity) : OrderedCustomListAdapter() { + val lastID: Long + get() = if (count > 0) getItem(count - 1).id else -1 + + val topID: Long + get() = if (count > 0) getItem(0).id else -1 + + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { + return Partials.getDirectMessageView(getItem(position), activity, convertView) + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/adapter/OrderedCustomListAdapter.java b/app/src/main/java/net/lacolaco/smileessence/view/adapter/OrderedCustomListAdapter.java deleted file mode 100644 index 3de58658..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/adapter/OrderedCustomListAdapter.java +++ /dev/null @@ -1,41 +0,0 @@ -package net.lacolaco.smileessence.view.adapter; - -import net.lacolaco.smileessence.entity.IdObject; - -import java.util.*; - -public abstract class OrderedCustomListAdapter extends CustomListAdapter { - private final Map treeMap; - - public OrderedCustomListAdapter() { - this(Long::compare); - } - - public OrderedCustomListAdapter(Comparator comparator) { - super(); - this.treeMap = new TreeMap<>(Collections.reverseOrder(comparator)); - } - - @Override - protected synchronized List getList() { - return new ArrayList<>(treeMap.values()); - } - - public synchronized void add(T item) { - treeMap.put(item.getId(), item); - } - - public synchronized void addAll(Collection items) { - for (T item : items) { - treeMap.put(item.getId(), item); - } - } - - public synchronized void clear() { - treeMap.clear(); - } - - public synchronized T remove(T item) { - return treeMap.remove(item.getId()); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/adapter/OrderedCustomListAdapter.kt b/app/src/main/java/net/lacolaco/smileessence/view/adapter/OrderedCustomListAdapter.kt new file mode 100644 index 00000000..53b1c824 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/adapter/OrderedCustomListAdapter.kt @@ -0,0 +1,35 @@ +package net.lacolaco.smileessence.view.adapter + +import net.lacolaco.smileessence.entity.IdObject + +import java.util.* + +abstract class OrderedCustomListAdapter +constructor(comparator: Comparator = Comparator { x, y -> java.lang.Long.compare(x, y) }) : CustomListAdapter() { + private val treeMap: MutableMap = TreeMap(Collections.reverseOrder(comparator)) + + override val list: List + @Synchronized get() = ArrayList(treeMap.values) + + @Synchronized + fun add(item: T) { + treeMap.put(item.id, item) + } + + @Synchronized + fun addAll(items: Collection) { + for (item in items) { + treeMap.put(item.id, item) + } + } + + @Synchronized + fun clear() { + treeMap.clear() + } + + @Synchronized + fun remove(item: T): T { + return treeMap.remove(item.id)!! + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/adapter/PageListAdapter.java b/app/src/main/java/net/lacolaco/smileessence/view/adapter/PageListAdapter.java deleted file mode 100644 index 76e72093..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/adapter/PageListAdapter.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.view.adapter; - -import android.os.Bundle; -import android.support.v13.app.FragmentPagerAdapter; -import net.lacolaco.smileessence.activity.MainActivity; -import net.lacolaco.smileessence.logging.Logger; -import net.lacolaco.smileessence.view.page.PageFragment; - -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class PageListAdapter extends FragmentPagerAdapter { - - // ------------------------------ FIELDS ------------------------------ - - private final List pages = new ArrayList<>(); - private final Map> fragmentCache = new HashMap<>(); - - // --------------------------- FragmentPagerAdapter --------------------------- - - public PageListAdapter(MainActivity _activity) { - super(_activity.getFragmentManager()); - } - - @Override - public synchronized PageFragment getItem(int position) { - PageFragment pf; - PageInfo info = pages.get(position); - try { - pf = info.getFragmentClass().newInstance(); - } catch (Exception e) { - Logger.error("should not happen: fragmentClass is private or Android is broken?"); - e.printStackTrace(); - throw new RuntimeException(e); - } - pf.setArguments(info.getArgs()); - fragmentCache.put(position, new WeakReference<>(pf)); - return pf; - } - - public synchronized PageFragment getCachedFragment(int pos) { - WeakReference wpf = fragmentCache.get(pos); - if (wpf == null) { - return null; - } else { - return wpf.get(); - } - } - - @Override - public synchronized int getCount() { - return pages.size(); - } - - // ------------------------ INTERFACE METHODS ------------------------ - - // -------------------------- OTHER METHODS -------------------------- - - public void addPage(Class klass, String name, Bundle args) { - this.addPage(klass, name, args, true); - } - - public void addPage(Class klass, String name, Bundle args, boolean notifyChanged) { - pages.add(new PageInfo(klass, name, args)); - if (notifyChanged) notifyDataSetChanged(); - } - - public synchronized boolean removePage(int position) { - //if (removePageWithoutNotify(position)) { - // refreshListNavigation(); - // return true; - //} - return pages.remove(position) != null; // TODO - } - - public String getName(int pos) { - return pages.get(pos).getName(); - } - - @Deprecated - public int getIndex(Class fragmentClass) { - for (int i = 0; i < pages.size(); ++i) { - if (pages.get(i).getFragmentClass() == fragmentClass) { - return i; - } - } - return -1; - } - - private static final class PageInfo { - private final Class fragmentClass; - private final Bundle args; - private final String name; - - PageInfo(Class _fragmentClass, String _name, Bundle _args) { - fragmentClass = _fragmentClass; - name = _name; - args = _args; - } - - public Class getFragmentClass() { - return fragmentClass; - } - - public String getName() { - return name; - } - - public Bundle getArgs() { - return args; - } - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/adapter/PageListAdapter.kt b/app/src/main/java/net/lacolaco/smileessence/view/adapter/PageListAdapter.kt new file mode 100644 index 00000000..34d158f0 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/adapter/PageListAdapter.kt @@ -0,0 +1,110 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.adapter + +import android.os.Bundle +import android.support.v13.app.FragmentPagerAdapter +import net.lacolaco.smileessence.activity.MainActivity +import net.lacolaco.smileessence.logging.Logger +import net.lacolaco.smileessence.view.page.PageFragment + +import java.lang.ref.WeakReference +import java.util.ArrayList +import java.util.HashMap + +class PageListAdapter +// --------------------------- FragmentPagerAdapter --------------------------- + +(_activity: MainActivity) : FragmentPagerAdapter(_activity.fragmentManager) { + + // ------------------------------ FIELDS ------------------------------ + + private val pages = ArrayList() + private val fragmentCache = HashMap>>() + + @Synchronized override fun getItem(position: Int): PageFragment<*> { + val pf: PageFragment<*> + val info = pages[position] + try { + pf = info.fragmentClass.newInstance() + } catch (e: Exception) { + Logger.error("should not happen: fragmentClass is private or Android is broken?") + e.printStackTrace() + throw RuntimeException(e) + } + + pf.arguments = info.args + fragmentCache.put(position, WeakReference(pf)) + return pf + } + + @Synchronized + fun getCachedFragment(pos: Int): PageFragment<*>? { + val wpf = fragmentCache[pos] + return wpf?.get() + } + + @Synchronized override fun getCount(): Int { + return pages.size + } + + // ------------------------ INTERFACE METHODS ------------------------ + + // -------------------------- OTHER METHODS -------------------------- + + fun addPage(klass: Class>, name: String, args: Bundle) { + this.addPage(klass, name, args, true) + } + + fun addPage(klass: Class>, name: String, args: Bundle, notifyChanged: Boolean) { + pages.add(PageInfo(klass, name, args)) + if (notifyChanged) notifyDataSetChanged() + } + + @Synchronized + fun removePage(position: Int): Boolean { + //if (removePageWithoutNotify(position)) { + // refreshListNavigation(); + // return true; + //} + return pages.removeAt(position) != null // TODO + } + + fun getName(pos: Int): String { + return pages[pos].name + } + + @Deprecated("") + fun getIndex(fragmentClass: Class>): Int { + for (i in pages.indices) { + if (pages[i].fragmentClass == fragmentClass) { + return i + } + } + return -1 + } + + private class PageInfo internal constructor(val fragmentClass: Class>, val name: String, val args: Bundle) +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/adapter/TimelineAdapter.java b/app/src/main/java/net/lacolaco/smileessence/view/adapter/TimelineAdapter.java deleted file mode 100644 index 0dbe8d53..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/adapter/TimelineAdapter.java +++ /dev/null @@ -1,39 +0,0 @@ -package net.lacolaco.smileessence.view.adapter; - -import android.app.Activity; -import android.view.View; -import android.view.ViewGroup; -import net.lacolaco.smileessence.entity.Tweet; -import net.lacolaco.smileessence.view.Partials; - -import java.util.*; - -public class TimelineAdapter extends OrderedCustomListAdapter { - private final Activity activity; - - public TimelineAdapter(Activity activity) { - super(); - this.activity = activity; - } - - public long getLastID() { - if (getCount() > 0) { - return getItem(getCount() - 1).getId(); - } else { - return -1; - } - } - - public long getTopID() { - if (getCount() > 0) { - return getItem(0).getId(); - } else { - return -1; - } - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - return Partials.getTweetView(getItem(position), activity, convertView, true); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/adapter/TimelineAdapter.kt b/app/src/main/java/net/lacolaco/smileessence/view/adapter/TimelineAdapter.kt new file mode 100644 index 00000000..750b63a0 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/adapter/TimelineAdapter.kt @@ -0,0 +1,29 @@ +package net.lacolaco.smileessence.view.adapter + +import android.app.Activity +import android.view.View +import android.view.ViewGroup +import net.lacolaco.smileessence.entity.Tweet +import net.lacolaco.smileessence.view.Partials + +import java.util.* + +class TimelineAdapter(private val activity: Activity) : OrderedCustomListAdapter() { + val lastID: Long + get() = if (count > 0) { + getItem(count - 1).id + } else { + -1 + } + + val topID: Long + get() = if (count > 0) { + getItem(0).id + } else { + -1 + } + + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { + return Partials.getTweetView(getItem(position), activity, convertView, true) + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/ConfirmDialogFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/ConfirmDialogFragment.java deleted file mode 100644 index 74dcc468..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/dialog/ConfirmDialogFragment.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.view.dialog; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.DialogInterface; -import android.os.Bundle; -import net.lacolaco.smileessence.R; -import net.lacolaco.smileessence.preference.UserPreferenceHelper; -import net.lacolaco.smileessence.view.DialogHelper; - -public abstract class ConfirmDialogFragment extends StackableDialogFragment { - - // ------------------------------ FIELDS ------------------------------ - - private static final String ARG_TEXT = "text"; - private final DialogInterface.OnClickListener listener = (dialog, which) -> { - onButtonClick(which); - dialog.dismiss(); - }; - private String text; - - // -------------------------- STATIC METHODS -------------------------- - - public static void show(Activity activity, String text, final Runnable onYes) { - show(activity, text, onYes, null, true); - } - - public static void show(Activity activity, String text, final Runnable onYes, boolean ignorable) { - show(activity, text, onYes, null, ignorable); - } - - public static void show(Activity activity, String text, final Runnable onOK, final Runnable onCancel, boolean ignorable) { - boolean confirm = UserPreferenceHelper.getInstance().get(R.string.key_setting_show_confirm_dialog, true); - if (!confirm && ignorable) { - onOK.run(); - return; - } - final ConfirmDialogFragment fragment = new ConfirmDialogFragment() { - @Override - public void onButtonClick(int which) { - switch (which) { - case DialogInterface.BUTTON_POSITIVE: { - if (onOK != null) { - dismiss(); - onOK.run(); - } - break; - } - case DialogInterface.BUTTON_NEGATIVE: { - if (onCancel != null) { - dismiss(); - onCancel.run(); - } - break; - } - } - } - }; - fragment.setText(text); - DialogHelper.showDialog(activity, fragment); - } - - // --------------------- GETTER / SETTER METHODS --------------------- - - public void setText(String text) { - Bundle args = new Bundle(); - args.putString(ARG_TEXT, text); - setArguments(args); - } - - // ------------------------ OVERRIDE METHODS ------------------------ - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - Bundle args = getArguments(); - if (args != null) { - text = args.getString(ARG_TEXT); - } - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - return new AlertDialog.Builder(getActivity()).setTitle(text) - .setCancelable(false) - .setPositiveButton(R.string.alert_dialog_ok, listener) - .setNegativeButton(R.string.alert_dialog_cancel, listener) - .create(); - } - - // -------------------------- OTHER METHODS -------------------------- - - protected abstract void onButtonClick(int which); -} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/ConfirmDialogFragment.kt b/app/src/main/java/net/lacolaco/smileessence/view/dialog/ConfirmDialogFragment.kt new file mode 100644 index 00000000..094aa18a --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/ConfirmDialogFragment.kt @@ -0,0 +1,119 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.dialog + +import android.app.Activity +import android.app.AlertDialog +import android.app.Dialog +import android.content.DialogInterface +import android.os.Bundle +import net.lacolaco.smileessence.R +import net.lacolaco.smileessence.preference.UserPreferenceHelper +import net.lacolaco.smileessence.view.DialogHelper + +abstract class ConfirmDialogFragment : StackableDialogFragment() { + private var text: String? = null + + // --------------------- GETTER / SETTER METHODS --------------------- + + fun setText(text: String) { + val args = Bundle() + args.putString(ARG_TEXT, text) + arguments = args + } + + // ------------------------ OVERRIDE METHODS ------------------------ + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + val args = arguments + if (args != null) { + text = args.getString(ARG_TEXT) + } + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + return AlertDialog.Builder(activity).setTitle(text) + .setCancelable(false) + .setPositiveButton(R.string.alert_dialog_ok, { dialog, which -> + onButtonClick(which) + dialog.dismiss() + }) + .setNegativeButton(R.string.alert_dialog_cancel, { dialog, which -> + onButtonClick(which) + dialog.dismiss() + }) + .create() + } + + // -------------------------- OTHER METHODS -------------------------- + + protected abstract fun onButtonClick(which: Int) + + companion object { + + // ------------------------------ FIELDS ------------------------------ + + private val ARG_TEXT = "text" + + // -------------------------- STATIC METHODS -------------------------- + + fun show(activity: Activity, text: String, onYes: () -> Unit) { + show(activity, text, onYes, null, true) + } + + fun show(activity: Activity, text: String, onYes: () -> Unit, ignorable: Boolean) { + show(activity, text, onYes, null, ignorable) + } + + fun show(activity: Activity, text: String, onOK: (() -> Unit)?, onCancel: (() -> Unit)?, ignorable: Boolean) { + val confirm = UserPreferenceHelper.instance.get(R.string.key_setting_show_confirm_dialog, true) + if (!confirm && ignorable) { + onOK!!() + return + } + val fragment = object : ConfirmDialogFragment() { + public override fun onButtonClick(which: Int) { + when (which) { + DialogInterface.BUTTON_POSITIVE -> { + if (onOK != null) { + dismiss() + onOK() + } + } + DialogInterface.BUTTON_NEGATIVE -> { + if (onCancel != null) { + dismiss() + onCancel() + } + } + } + } + } + fragment.setText(text) + DialogHelper.showDialog(activity, fragment) + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/DisposeDialog.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/DisposeDialog.java deleted file mode 100644 index eb3d3613..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/dialog/DisposeDialog.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.view.dialog; - -import android.app.Dialog; -import android.content.Context; - -/** - * Dialog for dispose soon. - */ -public final class DisposeDialog extends Dialog { - - public DisposeDialog(Context context) { - super(context); - } - - @Override - public void show() { - dismiss(); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/DisposeDialog.kt b/app/src/main/java/net/lacolaco/smileessence/view/dialog/DisposeDialog.kt new file mode 100644 index 00000000..3cd486bd --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/DisposeDialog.kt @@ -0,0 +1,37 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.dialog + +import android.app.Dialog +import android.content.Context + +/** + * Dialog for dispose soon. + */ +class DisposeDialog(context: Context) : Dialog(context) { + override fun show() { + dismiss() + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/EditTextDialogFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/EditTextDialogFragment.java deleted file mode 100644 index 8ce25145..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/dialog/EditTextDialogFragment.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.view.dialog; - -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.DialogFragment; -import android.os.Bundle; -import android.view.View; -import android.widget.EditText; -import net.lacolaco.smileessence.R; - -public abstract class EditTextDialogFragment extends DialogFragment { - - // ------------------------------ FIELDS ------------------------------ - - private static final String titleKey = "title"; - private static final String textKey = "text"; - private String title; - private String text; - - // ------------------------ OVERRIDE METHODS ------------------------ - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - Bundle args = getArguments(); - text = args.getString(textKey); - title = args.getString(titleKey); - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - View view = getActivity().getLayoutInflater().inflate(R.layout.part_edittext, null); - final EditText editText = (EditText) view.findViewById(R.id.part_edittext); - editText.setText(text); - return new AlertDialog.Builder(getActivity()) - .setTitle(title) - .setView(view) - .setPositiveButton(R.string.alert_dialog_ok, (dialog, which) -> { - onTextInput(editText.getText().toString()); - dialog.dismiss(); - }) - .setNegativeButton(R.string.alert_dialog_cancel, (dialog, which) -> dialog.dismiss()) - .create(); - } - - // -------------------------- OTHER METHODS -------------------------- - - public abstract void onTextInput(String text); - - public void setParams(String title, String text) { - Bundle args = new Bundle(); - args.putString(titleKey, title); - args.putString(textKey, text); - setArguments(args); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/EditTextDialogFragment.kt b/app/src/main/java/net/lacolaco/smileessence/view/dialog/EditTextDialogFragment.kt new file mode 100644 index 00000000..399b84ad --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/EditTextDialogFragment.kt @@ -0,0 +1,81 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.dialog + +import android.app.AlertDialog +import android.app.Dialog +import android.app.DialogFragment +import android.os.Bundle +import android.view.View +import android.widget.EditText +import net.lacolaco.smileessence.R + +abstract class EditTextDialogFragment : DialogFragment() { + private lateinit var title: String + private lateinit var text: String + + // ------------------------ OVERRIDE METHODS ------------------------ + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + val args = arguments + text = args.getString(textKey) + title = args.getString(titleKey) + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val view = activity.layoutInflater.inflate(R.layout.part_edittext, null) + val editText = view.findViewById(R.id.part_edittext) as EditText + editText.setText(text) + return AlertDialog.Builder(activity) + .setTitle(title) + .setView(view) + .setPositiveButton(R.string.alert_dialog_ok) { dialog, which -> + onTextInput(editText.text.toString()) + dialog.dismiss() + } + .setNegativeButton(R.string.alert_dialog_cancel) { dialog, which -> dialog.dismiss() } + .create() + } + + // -------------------------- OTHER METHODS -------------------------- + + abstract fun onTextInput(text: String) + + fun setParams(title: String, text: String) { + val args = Bundle() + args.putString(titleKey, title) + args.putString(textKey, text) + arguments = args + } + + companion object { + + // ------------------------------ FIELDS ------------------------------ + + private val titleKey = "title" + private val textKey = "text" + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/MessageDetailDialogFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/MessageDetailDialogFragment.java deleted file mode 100644 index f8a1e2e5..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/dialog/MessageDetailDialogFragment.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2015 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.view.dialog; - -import android.app.AlertDialog; -import android.app.Dialog; -import android.graphics.drawable.ColorDrawable; -import android.os.Bundle; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageButton; -import android.widget.ListView; -import android.widget.TextView; -import net.lacolaco.smileessence.R; -import net.lacolaco.smileessence.activity.MainActivity; -import net.lacolaco.smileessence.command.Command; -import net.lacolaco.smileessence.command.CommandAddHashtag; -import net.lacolaco.smileessence.command.CommandOpenURL; -import net.lacolaco.smileessence.command.CommandOpenUserDetail; -import net.lacolaco.smileessence.entity.DirectMessage; -import net.lacolaco.smileessence.preference.UserPreferenceHelper; -import net.lacolaco.smileessence.twitter.task.Messages; -import net.lacolaco.smileessence.util.SystemServiceHelper; -import net.lacolaco.smileessence.view.DialogHelper; -import net.lacolaco.smileessence.view.Partials; -import net.lacolaco.smileessence.view.adapter.CustomListAdapter; -import net.lacolaco.smileessence.view.adapter.MessageListAdapter; - -import java.util.ArrayList; -import java.util.List; - -public class MessageDetailDialogFragment extends StackableDialogFragment implements View.OnClickListener { - private static final String KEY_MESSAGE_ID = "message_id"; - private DirectMessage message; - - public static MessageDetailDialogFragment newInstance(DirectMessage message) { - MessageDetailDialogFragment obj = new MessageDetailDialogFragment(); - Bundle args = new Bundle(); - args.putLong(KEY_MESSAGE_ID, message.getId()); - obj.setArguments(args); - return obj; - } - - @Override - public void onClick(final View v) { - switch (v.getId()) { - case R.id.button_status_detail_reply: { - openSendMessageDialog(); - break; - } - case R.id.button_status_detail_delete: { - deleteMessage(); - break; - } - case R.id.button_status_detail_menu: { - openMenu(); - break; - } - default: { - dismiss(); - } - } - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - message = DirectMessage.fetch(getArguments().getLong(KEY_MESSAGE_ID)); - if (message == null) { - getWorld().notifyError(R.string.notice_error_get_messages); - return new DisposeDialog(getActivity()); - } - - View header = getTitleView(); - ListView listView = (ListView) header.findViewById(R.id.listview_status_detail_reply_to); - final MessageListAdapter adapter = new MessageListAdapter(getActivity()); - listView.setAdapter(adapter); - - // TODO: 効率的な探索どうする - DirectMessage replyTo = null; - // FIXME - // for (DirectMessage mes : DirectMessage.cached()) { - // if (message.getId() > mes.getId() && - // message.getRecipient() == mes.getSender() && - // message.getSender() == mes.getRecipient() && - // (replyTo == null || replyTo.getId() < mes.getId())) { - // replyTo = mes; - // } - // } - if (replyTo != null) { - listView.setVisibility(View.VISIBLE); - adapter.add(replyTo); - adapter.updateForce(); - } else { - listView.setVisibility(View.GONE); - } - - return new AlertDialog.Builder(getActivity()).setView(header).create(); - } - - // -------------------------- OTHER METHODS -------------------------- - - private void deleteMessage() { - ConfirmDialogFragment.show(getActivity(), getString(R.string.dialog_confirm_commands), () -> { - new Messages.DestroyTask(getWorld().getAccount(), message.getId()) - .onDone(x -> getWorld().notify(R.string.notice_message_delete_succeeded)) - .onFail(x -> getWorld().notifyError(R.string.notice_message_delete_failed)) - .execute(); - dismiss(); - }); - } - - private void openSendMessageDialog() { - DialogHelper.showDialog(getActivity(), SendMessageDialogFragment.newInstance(message.getSender())); - } - - private View getTitleView() { - MainActivity activity = (MainActivity) getActivity(); - - View view = activity.getLayoutInflater().inflate(R.layout.dialog_status_detail, null); - - View messageHeader = Partials.getDirectMessageView(message, activity, view.findViewById(R.id.layout_status_header)); - messageHeader.setClickable(false); - - view.setBackgroundColor(((ColorDrawable) messageHeader.getBackground()).getColor()); - updateViewButtons(view); - updateViewMenu(view); - - // status only parts - view.findViewById(R.id.detail_dialog_divider_top).setVisibility(View.GONE); - view.findViewById(R.id.button_status_detail_retweet).setVisibility(View.GONE); - view.findViewById(R.id.button_status_detail_favorite).setVisibility(View.GONE); - view.findViewById(R.id.image_status_detail_fav_count).setVisibility(View.GONE); - view.findViewById(R.id.image_status_detail_rt_count).setVisibility(View.GONE); - - return view; - } - - private void updateViewButtons(View view) { - //--- buttons - ImageButton reply = (ImageButton) view.findViewById(R.id.button_status_detail_reply); - reply.setOnClickListener(this); - - ImageButton delete = (ImageButton) view.findViewById(R.id.button_status_detail_delete); - delete.setOnClickListener(this); - delete.setVisibility(View.VISIBLE); - } - - private void updateViewMenu(View view) { - // -- menu dialog - ImageButton menu = (ImageButton) view.findViewById(R.id.button_status_detail_menu); - menu.setOnClickListener(this); - - // -- menu embedded in dialog - View divider = view.findViewById(R.id.detail_dialog_divider_bottom); - ListView listView = (ListView) view.findViewById(R.id.listview_status_detail_menu); - List commands = getCommands(); - if (commands.size() > 0) { - divider.setVisibility(View.VISIBLE); - listView.setVisibility(View.VISIBLE); - final CustomListAdapter adapter = new CustomListAdapter() { - @Override - public View getView(int position, View convertView, ViewGroup parent) { - if (convertView == null) { - convertView = getActivity().getLayoutInflater().inflate(R.layout.menu_item_simple_text, null); - } - TextView textView = (TextView) convertView.findViewById(R.id.list_item_textview); - textView.setTextSize(UserPreferenceHelper.getInstance().getTextSize()); - textView.setText(getItem(position).getText()); - return convertView; - } - - @Override - protected List getList() { - return commands; - } - }; - adapter.update(); - listView.setAdapter(adapter); - listView.setOnItemClickListener((parent, view1, position, id) -> { - Command command = (Command) parent.getItemAtPosition(position); - command.execute(); - }); - } else { - divider.setVisibility(View.GONE); - listView.setVisibility(View.GONE); - } - } - - private List getCommands() { - MainActivity activity = (MainActivity) getActivity(); - List commands = new ArrayList<>(); - // Mentions - if (message.getSender() != message.getRecipient()) { - commands.add(new CommandOpenUserDetail(activity, message.getRecipient().getScreenName())); - } - for (String screenName : message.getMentions()) { - commands.add(new CommandOpenUserDetail(activity, screenName)); - } - for (String hashtag : message.getHashtags()) { - commands.add(new CommandAddHashtag(activity, hashtag)); - } - // URL - for (String url : message.getUrlsExpanded()) { - commands.add(new CommandOpenURL(activity, url)); - } - for (String url : message.getMediaUrls()) { - commands.add(new CommandOpenURL(activity, url)); - } - return commands; - } - - private void openMenu() { - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - builder.setTitle("@" + message.getSender().getScreenName() + ": " + message.getText()) - .setItems(R.array.message_commands, (dialog, which) -> { - switch (which) { - case 0: - SystemServiceHelper.copyToClipboard(getActivity(), "message text", message.getText()); - getWorld().notify(R.string.notice_copy_clipboard); - break; - default: - throw new IllegalStateException(); - } - }); - AlertDialog dialog = builder.create(); - dialog.show(); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/MessageDetailDialogFragment.kt b/app/src/main/java/net/lacolaco/smileessence/view/dialog/MessageDetailDialogFragment.kt new file mode 100644 index 00000000..36f7584f --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/MessageDetailDialogFragment.kt @@ -0,0 +1,246 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2015 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.dialog + +import android.app.AlertDialog +import android.app.Dialog +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.View +import android.view.ViewGroup +import android.widget.ImageButton +import android.widget.ListView +import android.widget.TextView +import net.lacolaco.smileessence.R +import net.lacolaco.smileessence.activity.MainActivity +import net.lacolaco.smileessence.command.Command +import net.lacolaco.smileessence.command.CommandAddHashtag +import net.lacolaco.smileessence.command.CommandOpenURL +import net.lacolaco.smileessence.command.CommandOpenUserDetail +import net.lacolaco.smileessence.entity.DirectMessage +import net.lacolaco.smileessence.preference.UserPreferenceHelper +import net.lacolaco.smileessence.twitter.task.Messages +import net.lacolaco.smileessence.util.SystemServiceHelper +import net.lacolaco.smileessence.view.DialogHelper +import net.lacolaco.smileessence.view.Partials +import net.lacolaco.smileessence.view.adapter.CustomListAdapter +import net.lacolaco.smileessence.view.adapter.MessageListAdapter + +import java.util.ArrayList + +class MessageDetailDialogFragment : StackableDialogFragment(), View.OnClickListener { + private lateinit var message: DirectMessage + + override fun onClick(v: View) { + when (v.id) { + R.id.button_status_detail_reply -> { + openSendMessageDialog() + } + R.id.button_status_detail_delete -> { + deleteMessage() + } + R.id.button_status_detail_menu -> { + openMenu() + } + else -> { + dismiss() + } + } + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val found = DirectMessage.fetch(arguments.getLong(KEY_MESSAGE_ID)) + if (found == null) { + world.notifyError(R.string.notice_error_get_messages) + return DisposeDialog(activity) + } + message = found + + val header = titleView + val listView = header.findViewById(R.id.listview_status_detail_reply_to) as ListView + val adapter = MessageListAdapter(activity) + listView.adapter = adapter + + // TODO: 効率的な探索どうする + val replyTo: DirectMessage? = null + // FIXME + // for (DirectMessage mes : DirectMessage.cached()) { + // if (message.getId() > mes.getId() && + // message.getRecipient() == mes.getSender() && + // message.getSender() == mes.getRecipient() && + // (replyTo == null || replyTo.getId() < mes.getId())) { + // replyTo = mes; + // } + // } + if (replyTo != null) { + listView.visibility = View.VISIBLE + adapter.add(replyTo) + adapter.updateForce() + } else { + listView.visibility = View.GONE + } + + return AlertDialog.Builder(activity).setView(header).create() + } + + // -------------------------- OTHER METHODS -------------------------- + + private fun deleteMessage() { + ConfirmDialogFragment.show(activity, getString(R.string.dialog_confirm_commands)) { + Messages.DestroyTask(world.account, message.id) + .onDone { x -> world.notify(R.string.notice_message_delete_succeeded) } + .onFail { x -> world.notifyError(R.string.notice_message_delete_failed) } + .execute() + dismiss() + } + } + + private fun openSendMessageDialog() { + DialogHelper.showDialog(activity, SendMessageDialogFragment.newInstance(message.sender)) + } + + private // status only parts + val titleView: View + get() { + val activity = activity as MainActivity + + val view = activity.layoutInflater.inflate(R.layout.dialog_status_detail, null) + + val messageHeader = Partials.getDirectMessageView(message, activity, view.findViewById(R.id.layout_status_header)) + messageHeader.isClickable = false + + view.setBackgroundColor((messageHeader.background as ColorDrawable).color) + updateViewButtons(view) + updateViewMenu(view) + view.findViewById(R.id.detail_dialog_divider_top).visibility = View.GONE + view.findViewById(R.id.button_status_detail_retweet).visibility = View.GONE + view.findViewById(R.id.button_status_detail_favorite).visibility = View.GONE + view.findViewById(R.id.image_status_detail_fav_count).visibility = View.GONE + view.findViewById(R.id.image_status_detail_rt_count).visibility = View.GONE + + return view + } + + private fun updateViewButtons(view: View) { + //--- buttons + val reply = view.findViewById(R.id.button_status_detail_reply) as ImageButton + reply.setOnClickListener(this) + + val delete = view.findViewById(R.id.button_status_detail_delete) as ImageButton + delete.setOnClickListener(this) + delete.visibility = View.VISIBLE + } + + private fun updateViewMenu(view: View) { + // -- menu dialog + val menu = view.findViewById(R.id.button_status_detail_menu) as ImageButton + menu.setOnClickListener(this) + + // -- menu embedded in dialog + val divider = view.findViewById(R.id.detail_dialog_divider_bottom) + val listView = view.findViewById(R.id.listview_status_detail_menu) as ListView + val commands = commands + if (commands.size > 0) { + divider.visibility = View.VISIBLE + listView.visibility = View.VISIBLE + val adapter = object : CustomListAdapter() { + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { + var convertView = convertView + if (convertView == null) { + convertView = activity.layoutInflater.inflate(R.layout.menu_item_simple_text, null) + } + val textView = convertView!!.findViewById(R.id.list_item_textview) as TextView + textView.textSize = UserPreferenceHelper.instance.textSize.toFloat() + textView.text = getItem(position).text + return convertView + } + + override val list: List + get() = commands + } + adapter.update() + listView.adapter = adapter + listView.setOnItemClickListener { parent, view1, position, id -> + val command = parent.getItemAtPosition(position) as Command + command.execute() + } + } else { + divider.visibility = View.GONE + listView.visibility = View.GONE + } + } + + private // Mentions + // URL + val commands: List + get() { + val activity = activity as MainActivity + val commands = ArrayList() + if (message.sender !== message.recipient) { + commands.add(CommandOpenUserDetail(activity, message.recipient.screenName)) + } + for (screenName in message.mentions) { + commands.add(CommandOpenUserDetail(activity, screenName)) + } + for (hashtag in message.hashtags) { + commands.add(CommandAddHashtag(activity, hashtag)) + } + for (url in message.urlsExpanded) { + commands.add(CommandOpenURL(activity, url)) + } + for (url in message.mediaUrls) { + commands.add(CommandOpenURL(activity, url)) + } + return commands + } + + private fun openMenu() { + val builder = AlertDialog.Builder(activity) + builder.setTitle("@" + message.sender.screenName + ": " + message.text) + .setItems(R.array.message_commands) { dialog, which -> + when (which) { + 0 -> { + SystemServiceHelper.copyToClipboard(activity, "message text", message.text) + world.notify(R.string.notice_copy_clipboard) + } + else -> throw IllegalStateException() + } + } + val dialog = builder.create() + dialog.show() + } + + companion object { + private val KEY_MESSAGE_ID = "message_id" + + fun newInstance(message: DirectMessage): MessageDetailDialogFragment { + val obj = MessageDetailDialogFragment() + val args = Bundle() + args.putLong(KEY_MESSAGE_ID, message.id) + obj.arguments = args + return obj + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/SendMessageDialogFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/SendMessageDialogFragment.java deleted file mode 100644 index 20917d8f..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/dialog/SendMessageDialogFragment.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.view.dialog; - -import android.app.AlertDialog; -import android.app.Dialog; -import android.os.Bundle; -import android.support.v4.content.ContextCompat; -import android.text.Editable; -import android.text.TextUtils; -import android.text.TextWatcher; -import android.view.View; -import android.widget.Button; -import android.widget.EditText; -import android.widget.ImageButton; -import android.widget.TextView; -import com.twitter.Validator; -import net.lacolaco.smileessence.Application; -import net.lacolaco.smileessence.R; -import net.lacolaco.smileessence.entity.User; -import net.lacolaco.smileessence.twitter.task.Messages; -import net.lacolaco.smileessence.util.SystemServiceHelper; - -public class SendMessageDialogFragment extends StackableDialogFragment implements TextWatcher, View.OnClickListener { - private static final String KEY_RECIPIENT_ID = "KEY_RECIPIENT_ID"; - private User recipient; - private EditText editText; - private TextView textViewCount; - private Button buttonSend; - - public static SendMessageDialogFragment newInstance(User recipient) { - SendMessageDialogFragment obj = new SendMessageDialogFragment(); - Bundle args = new Bundle(); - args.putLong(KEY_RECIPIENT_ID, recipient.getId()); - obj.setArguments(args); - return obj; - } - @Override - public void onClick(View v) { - int id = v.getId(); - switch (id) { - case R.id.button_send_message: { - sendMessage(); - break; - } - case R.id.button_send_message_delete: { - deleteMessage(); - } - } - } - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - Validator validator = new Validator(); - int remainingCount = 140 - validator.getTweetLength(s.toString()); - textViewCount.setText(String.valueOf(remainingCount)); - if (remainingCount == 140 || remainingCount < 0) { - textViewCount.setTextColor(ContextCompat.getColor(getActivity(), R.color.red)); - } else { - textViewCount.setTextAppearance(getActivity(), android.R.style.TextAppearance_Widget_TextView); - } - } - - @Override - public void afterTextChanged(Editable s) { - - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - recipient = User.fetch(getArguments().getLong(KEY_RECIPIENT_ID)); - View view = getActivity().getLayoutInflater().inflate(R.layout.dialog_send_message, null); - TextView textViewName = (TextView) view.findViewById(R.id.textview_send_message_name); - textViewName.setText("To: @" + recipient.getScreenName()); - textViewCount = (TextView) view.findViewById(R.id.textview_send_message_count); - editText = (EditText) view.findViewById(R.id.edittext_send_message); - editText.addTextChangedListener(this); - buttonSend = (Button) view.findViewById(R.id.button_send_message); - buttonSend.setOnClickListener(this); - ImageButton buttonDelete = (ImageButton) view.findViewById(R.id.button_send_message_delete); - buttonDelete.setOnClickListener(this); - editText.setText(""); - return new AlertDialog.Builder(getActivity()) - .setView(view) - .create(); - } - - private void deleteMessage() { - editText.setText(""); - } - - private void sendMessage() { - SystemServiceHelper.hideIM(getActivity(), editText); - String text = editText.getText().toString(); - new Messages.CreateTask(getWorld().getAccount(), recipient.getId(), text) - .onDoneUI(m -> { - getWorld().addDirectMessage(m); - getWorld().notify(R.string.notice_message_send_succeeded); - dismiss(); - }) - .onFail(e -> getWorld().notifyError(R.string.notice_message_send_failed, e)) - .execute(); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/SendMessageDialogFragment.kt b/app/src/main/java/net/lacolaco/smileessence/view/dialog/SendMessageDialogFragment.kt new file mode 100644 index 00000000..fb7e9d2f --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/SendMessageDialogFragment.kt @@ -0,0 +1,127 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.dialog + +import android.app.AlertDialog +import android.app.Dialog +import android.os.Bundle +import android.support.v4.content.ContextCompat +import android.text.Editable +import android.text.TextUtils +import android.text.TextWatcher +import android.view.View +import android.widget.Button +import android.widget.EditText +import android.widget.ImageButton +import android.widget.TextView +import com.twitter.Validator +import net.lacolaco.smileessence.Application +import net.lacolaco.smileessence.R +import net.lacolaco.smileessence.entity.User +import net.lacolaco.smileessence.twitter.task.Messages +import net.lacolaco.smileessence.util.SystemServiceHelper + +class SendMessageDialogFragment : StackableDialogFragment(), TextWatcher, View.OnClickListener { + private var recipient: User? = null + private var editText: EditText? = null + private var textViewCount: TextView? = null + private var buttonSend: Button? = null + override fun onClick(v: View) { + val id = v.id + when (id) { + R.id.button_send_message -> { + sendMessage() + } + R.id.button_send_message_delete -> { + deleteMessage() + } + } + } + + override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { + + } + + override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { + val validator = Validator() + val remainingCount = 140 - validator.getTweetLength(s.toString()) + textViewCount!!.text = remainingCount.toString() + if (remainingCount == 140 || remainingCount < 0) { + textViewCount!!.setTextColor(ContextCompat.getColor(activity, R.color.red)) + } else { + textViewCount!!.setTextAppearance(activity, android.R.style.TextAppearance_Widget_TextView) + } + } + + override fun afterTextChanged(s: Editable) { + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + recipient = User.fetch(arguments.getLong(KEY_RECIPIENT_ID)) + val view = activity.layoutInflater.inflate(R.layout.dialog_send_message, null) + val textViewName = view.findViewById(R.id.textview_send_message_name) as TextView + textViewName.text = "To: @" + recipient!!.screenName + textViewCount = view.findViewById(R.id.textview_send_message_count) as TextView + editText = view.findViewById(R.id.edittext_send_message) as EditText + editText!!.addTextChangedListener(this) + buttonSend = view.findViewById(R.id.button_send_message) as Button + buttonSend!!.setOnClickListener(this) + val buttonDelete = view.findViewById(R.id.button_send_message_delete) as ImageButton + buttonDelete.setOnClickListener(this) + editText!!.setText("") + return AlertDialog.Builder(activity) + .setView(view) + .create() + } + + private fun deleteMessage() { + editText!!.setText("") + } + + private fun sendMessage() { + SystemServiceHelper.hideIM(activity, editText) + val text = editText!!.text.toString() + Messages.CreateTask(world.account, recipient!!.id, text) + .onDoneUI { m -> + world.addDirectMessage(m) + world.notify(R.string.notice_message_send_succeeded) + dismiss() + } + .onFail { e -> world.notifyError(R.string.notice_message_send_failed, e) } + .execute() + } + + companion object { + private val KEY_RECIPIENT_ID = "KEY_RECIPIENT_ID" + + fun newInstance(recipient: User): SendMessageDialogFragment { + val obj = SendMessageDialogFragment() + val args = Bundle() + args.putLong(KEY_RECIPIENT_ID, recipient.id) + obj.arguments = args + return obj + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/StackableDialogFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/StackableDialogFragment.java deleted file mode 100644 index 848c6465..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/dialog/StackableDialogFragment.java +++ /dev/null @@ -1,28 +0,0 @@ -package net.lacolaco.smileessence.view.dialog; - -import android.app.DialogFragment; -import net.lacolaco.smileessence.World; -import net.lacolaco.smileessence.activity.MainActivity; -import net.lacolaco.smileessence.view.DialogHelper; - -/** - * Only used by MainActivity. - */ -public class StackableDialogFragment extends DialogFragment { - @Override - public void dismiss() { - super.dismiss(); - DialogHelper.unregisterDialog(getTag()); - } - - @Override - public void dismissAllowingStateLoss() { - super.dismissAllowingStateLoss(); - DialogHelper.unregisterDialog(getTag()); - } - - protected World getWorld() { - final MainActivity activity = (MainActivity) getActivity(); - return activity.getWorld(); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/StackableDialogFragment.kt b/app/src/main/java/net/lacolaco/smileessence/view/dialog/StackableDialogFragment.kt new file mode 100644 index 00000000..7822cfe3 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/StackableDialogFragment.kt @@ -0,0 +1,25 @@ +package net.lacolaco.smileessence.view.dialog + +import android.app.DialogFragment +import net.lacolaco.smileessence.World +import net.lacolaco.smileessence.activity.MainActivity +import net.lacolaco.smileessence.view.DialogHelper + +/** + * Only used by MainActivity. + */ +open class StackableDialogFragment : DialogFragment() { + override fun dismiss() { + super.dismiss() + DialogHelper.unregisterDialog(tag) + } + + override fun dismissAllowingStateLoss() { + super.dismissAllowingStateLoss() + DialogHelper.unregisterDialog(tag) + } + + protected val world: World by lazy { + (activity as MainActivity).world + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/StatusDetailDialogFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/StatusDetailDialogFragment.java deleted file mode 100644 index 5b2ee58c..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/dialog/StatusDetailDialogFragment.java +++ /dev/null @@ -1,348 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.view.dialog; - -import android.app.AlertDialog; -import android.app.Dialog; -import android.graphics.drawable.ColorDrawable; -import android.os.Bundle; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.ListView; -import android.widget.TextView; -import net.lacolaco.smileessence.Application; -import net.lacolaco.smileessence.R; -import net.lacolaco.smileessence.activity.MainActivity; -import net.lacolaco.smileessence.command.Command; -import net.lacolaco.smileessence.command.CommandAddHashtag; -import net.lacolaco.smileessence.command.CommandOpenURL; -import net.lacolaco.smileessence.command.CommandOpenUserDetail; -import net.lacolaco.smileessence.data.Account; -import net.lacolaco.smileessence.entity.RBinding; -import net.lacolaco.smileessence.entity.Tweet; -import net.lacolaco.smileessence.preference.UserPreferenceHelper; -import net.lacolaco.smileessence.twitter.task.TweetReactions; -import net.lacolaco.smileessence.twitter.task.Tweets; -import net.lacolaco.smileessence.util.IntentUtils; -import net.lacolaco.smileessence.util.SystemServiceHelper; -import net.lacolaco.smileessence.util.UIObserverBundle; -import net.lacolaco.smileessence.view.DialogHelper; -import net.lacolaco.smileessence.view.Partials; -import net.lacolaco.smileessence.view.ToggleableImageButton; -import net.lacolaco.smileessence.view.adapter.CustomListAdapter; -import net.lacolaco.smileessence.view.adapter.TimelineAdapter; - -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.LinkedHashSet; -import java.util.List; - -public class StatusDetailDialogFragment extends StackableDialogFragment implements View.OnClickListener { - private static final String KEY_STATUS_ID = "status_id"; - private Tweet tweet; - - public static StatusDetailDialogFragment newInstance(Tweet tweet) { - StatusDetailDialogFragment obj = new StatusDetailDialogFragment(); - Bundle args = new Bundle(); - args.putLong(KEY_STATUS_ID, tweet.getId()); - obj.setArguments(args); - return obj; - } - - @Override - public void onClick(final View v) { - switch (v.getId()) { - case R.id.button_status_detail_reply: { - Tweet originalTweet = tweet.getOriginalTweet(); - - StringBuilder builder = new StringBuilder(); - builder.append("@" + originalTweet.getUser().getScreenName() + " "); - - for (String screenName : originalTweet.getMentions()) { - if (!screenName.equals(getWorld().getAccount().getUser().getScreenName())) - builder.append("@" + screenName + " "); - } - String text = builder.toString(); - int selStart = originalTweet.getUser().getScreenName().length() + 2; // "@" and " " - - getWorld().getPostState().beginTransaction() - .clear() - .insertText(0, text) - .setInReplyTo(originalTweet) - .setSelection(selStart, text.length()) - .commitWithOpen((MainActivity) getActivity()); - break; - } - case R.id.button_status_detail_retweet: { - Account account = getWorld().getAccount(); - confirm(() -> { - if (tweet.isRetweetedBy(account.getUserId())) { - new Tweets.DestroyTask(account, tweet.getRetweetIdBy(account.getUserId())) - .onDone(t -> getWorld().notify(R.string.notice_status_delete_succeeded)) - .onFail(e -> getWorld().notifyError(R.string.notice_status_delete_failed)) - .execute(); - dismiss(); - } else { - new TweetReactions.RetweetTask(account, tweet.getId()) - .onDone(x -> getWorld().notify(R.string.notice_retweet_succeeded)) - .onFail(x -> getWorld().notifyError(R.string.notice_retweet_failed)) - .execute(); - } - }); - break; - } - case R.id.button_status_detail_favorite: { - Account account = getWorld().getAccount(); - if (tweet.isFavoritedBy(account.getUserId())) { - new TweetReactions.UnfavoriteTask(account, tweet.getId()) - .onDone(x -> getWorld().notify(R.string.notice_unfavorite_succeeded)) - .onFail(x -> getWorld().notifyError(R.string.notice_unfavorite_failed)) - .execute(); - } else { - new TweetReactions.FavoriteTask(account, tweet.getId()) - .onDone(x -> getWorld().notify(R.string.notice_favorite_succeeded)) - .onFail(x -> getWorld().notifyError(R.string.notice_favorite_failed)) - .execute(); - } - break; - } - case R.id.button_status_detail_delete: { - confirm(() -> { - new Tweets.DestroyTask(getWorld().getAccount(), tweet.getOriginalTweet().getId()) - .onDone(t -> getWorld().notify(R.string.notice_status_delete_succeeded)) - .onFail(e -> getWorld().notifyError(R.string.notice_status_delete_failed)) - .execute(); - dismiss(); - }); - break; - } - case R.id.button_status_detail_menu: { - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - builder.setTitle("@" + tweet.getUser().getScreenName() + ": " + tweet.getText()) - .setItems(R.array.status_commands, (dialog, which) -> { - switch (which) { - case 0: - String text = String.format("@%s ", tweet.getOriginalTweet().getUser().getScreenName()); - getWorld().getPostState().beginTransaction().insertText(0, text).moveCursor(text.length()).commit(); - getWorld().notify(R.string.notice_add_to_reply); - break; - case 1: - TalkChainDialogFragment dialogFragment = new TalkChainDialogFragment(); - dialogFragment.setStatusID(tweet.getOriginalTweet().getId()); - DialogHelper.showDialog(getActivity(), dialogFragment); - break; - case 2: - IntentUtils.openUri(getActivity(), tweet.getOriginalTweet().getTwitterUrl()); - break; - case 3: - SystemServiceHelper.copyToClipboard(getActivity(), "tweet text", tweet.getOriginalTweet().getText()); - getWorld().notify(R.string.notice_copy_clipboard); - break; - case 4: - String statusURL = tweet.getOriginalTweet().getTwitterUrl(); - SystemServiceHelper.copyToClipboard(getActivity(), "tweet url", statusURL); - getWorld().notify(R.string.notice_copy_clipboard); - break; - default: - throw new IllegalStateException(); - } - }); - AlertDialog dialog = builder.create(); - dialog.show(); - break; - } - default: { - dismiss(); - } - } - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - tweet = Tweet.fetch(getArguments().getLong(KEY_STATUS_ID)); - if (tweet == null) { // trying to open deleted tweet? - getWorld().notifyError(R.string.notice_error_show_status); - return new DisposeDialog(getActivity()); - } - - View view = getActivity().getLayoutInflater().inflate(R.layout.dialog_status_detail, null); - UIObserverBundle bundle = new UIObserverBundle(); - view.setTag(bundle); - - View statusHeader = Partials.getTweetView(tweet, getActivity(), view.findViewById(R.id.layout_status_header), true); - statusHeader.setClickable(false); - - view.setBackgroundColor(((ColorDrawable) statusHeader.getBackground()).getColor()); - updateViewReactions(view); - updateViewButtons(view); - setupViewMenu(view); - - final WeakReference weakView = new WeakReference<>(view); - bundle.attach(tweet.getOriginalTweet(), changes -> { - View strongView = weakView.get(); - if (strongView != null && getActivity() != null) { - if (changes.contains(RBinding.REACTION_COUNT)) - updateViewReactions(strongView); - if (changes.contains(RBinding.FAVORITERS) || changes.contains(RBinding.RETWEETERS)) - updateViewButtons(strongView); - } - }); - - ListView listView = (ListView) view.findViewById(R.id.listview_status_detail_reply_to); - final TimelineAdapter adapter = new TimelineAdapter(getActivity()); - listView.setAdapter(adapter); - - View replyDivider = view.findViewById(R.id.detail_dialog_divider_top); - - if (tweet.getInReplyToStatusId() != -1) { - replyDivider.setVisibility(View.VISIBLE); - listView.setVisibility(View.VISIBLE); - Tweet.fetchTask(tweet.getInReplyToStatusId(), getWorld().getAccount()) - .onDoneUI(replyTo -> { - adapter.add(replyTo); - adapter.update(); - }) - .execute(); - } else { - replyDivider.setVisibility(View.GONE); - listView.setVisibility(View.GONE); - } - - return new AlertDialog.Builder(getActivity()).setView(view).create(); - } - - private void updateViewReactions(View view) { - ImageView favCountIcon = (ImageView) view.findViewById(R.id.image_status_detail_fav_count); - TextView favCountText = (TextView) view.findViewById(R.id.textview_status_detail_fav_count); - if (tweet.getFavoriteCount() > 0) { - favCountText.setText(Integer.toString(tweet.getFavoriteCount())); - favCountIcon.setVisibility(View.VISIBLE); - favCountText.setVisibility(View.VISIBLE); - } else { - favCountIcon.setVisibility(View.GONE); - favCountText.setVisibility(View.GONE); - } - - ImageView rtCountIcon = (ImageView) view.findViewById(R.id.image_status_detail_rt_count); - TextView rtCountText = (TextView) view.findViewById(R.id.textview_status_detail_rt_count); - if (tweet.getRetweetCount() > 0) { - rtCountText.setText(Integer.toString(tweet.getRetweetCount())); - rtCountIcon.setVisibility(View.VISIBLE); - rtCountText.setVisibility(View.VISIBLE); - } else { - rtCountIcon.setVisibility(View.GONE); - rtCountText.setVisibility(View.GONE); - } - } - - private void updateViewButtons(View view) { - Account account = getWorld().getAccount(); - - //--- buttons - ImageButton reply = (ImageButton) view.findViewById(R.id.button_status_detail_reply); - reply.setOnClickListener(this); - - ToggleableImageButton retweet = (ToggleableImageButton) view.findViewById(R.id.button_status_detail_retweet); - retweet.setOnClickListener(this); - retweet.setState(tweet.isRetweetedBy(account.getUserId())); - - ToggleableImageButton favorite = (ToggleableImageButton) view.findViewById(R.id.button_status_detail_favorite); - favorite.setOnClickListener(this); - favorite.setState(tweet.isFavoritedBy(account.getUserId())); - - ImageButton delete = (ImageButton) view.findViewById(R.id.button_status_detail_delete); - delete.setOnClickListener(this); - delete.setVisibility(tweet.getOriginalTweet().getUser() == account.getUser() ? View.VISIBLE : View.GONE); - - ImageButton menu = (ImageButton) view.findViewById(R.id.button_status_detail_menu); - menu.setOnClickListener(this); - } - - private void setupViewMenu(View view) { - View divider = view.findViewById(R.id.detail_dialog_divider_bottom); - ListView listView = (ListView) view.findViewById(R.id.listview_status_detail_menu); - List commands = getCommands(); - if (commands.size() > 0) { - divider.setVisibility(View.VISIBLE); - listView.setVisibility(View.VISIBLE); - final CustomListAdapter adapter = new CustomListAdapter() { - @Override - public View getView(int position, View convertView, ViewGroup parent) { - if (convertView == null) { - convertView = getActivity().getLayoutInflater().inflate(R.layout.menu_item_simple_text, null); - } - TextView textView = (TextView) convertView.findViewById(R.id.list_item_textview); - textView.setTextSize(UserPreferenceHelper.getInstance().getTextSize()); - textView.setText(getItem(position).getText()); - return convertView; - } - - @Override - protected List getList() { - return commands; - } - }; - adapter.update(); - listView.setAdapter(adapter); - listView.setOnItemClickListener((parent, view1, position, id) -> { - Command command = (Command) parent.getItemAtPosition(position); - command.execute(); - }); - } else { - divider.setVisibility(View.GONE); - listView.setVisibility(View.GONE); - } - } - - private void confirm(Runnable onYes) { - ConfirmDialogFragment.show(getActivity(), getString(R.string.dialog_confirm_commands), onYes); - } - - private List getCommands() { - MainActivity activity = (MainActivity) getActivity(); - ArrayList commands = new ArrayList<>(); - // Retweeter - if (tweet.getRetweetedTweet() != null && tweet.getUser() != tweet.getRetweetedTweet().getUser()) - commands.add(new CommandOpenUserDetail(activity, tweet.getUser().getScreenName())); - // Mentions - for (String screenName : new ArrayList<>(new LinkedHashSet<>(tweet.getMentions()))) { // Array#uniq - commands.add(new CommandOpenUserDetail(activity, screenName)); - } - // Hashtags - for (String hashtag : tweet.getHashtags()) { - commands.add(new CommandAddHashtag(activity, hashtag)); - } - // URL - for (String url : tweet.getUrlsExpanded()) { - commands.add(new CommandOpenURL(activity, url)); - } - for (String url : tweet.getMediaUrls()) { - commands.add(new CommandOpenURL(activity, url)); - } - return commands; - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/StatusDetailDialogFragment.kt b/app/src/main/java/net/lacolaco/smileessence/view/dialog/StatusDetailDialogFragment.kt new file mode 100644 index 00000000..c18b6b4d --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/StatusDetailDialogFragment.kt @@ -0,0 +1,339 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.dialog + +import android.app.AlertDialog +import android.app.Dialog +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.View +import android.view.ViewGroup +import android.widget.ImageButton +import android.widget.ImageView +import android.widget.ListView +import android.widget.TextView +import net.lacolaco.smileessence.Application +import net.lacolaco.smileessence.R +import net.lacolaco.smileessence.activity.MainActivity +import net.lacolaco.smileessence.command.Command +import net.lacolaco.smileessence.command.CommandAddHashtag +import net.lacolaco.smileessence.command.CommandOpenURL +import net.lacolaco.smileessence.command.CommandOpenUserDetail +import net.lacolaco.smileessence.data.Account +import net.lacolaco.smileessence.entity.RBinding +import net.lacolaco.smileessence.entity.Tweet +import net.lacolaco.smileessence.preference.UserPreferenceHelper +import net.lacolaco.smileessence.twitter.task.TweetReactions +import net.lacolaco.smileessence.twitter.task.Tweets +import net.lacolaco.smileessence.util.IntentUtils +import net.lacolaco.smileessence.util.SystemServiceHelper +import net.lacolaco.smileessence.util.UIObserverBundle +import net.lacolaco.smileessence.view.DialogHelper +import net.lacolaco.smileessence.view.Partials +import net.lacolaco.smileessence.view.ToggleableImageButton +import net.lacolaco.smileessence.view.adapter.CustomListAdapter +import net.lacolaco.smileessence.view.adapter.TimelineAdapter + +import java.lang.ref.WeakReference +import java.util.ArrayList +import java.util.LinkedHashSet + +class StatusDetailDialogFragment : StackableDialogFragment(), View.OnClickListener { + private lateinit var tweet: Tweet + + override fun onClick(v: View) { + when (v.id) { + R.id.button_status_detail_reply -> { + val originalTweet = tweet.originalTweet + + val builder = StringBuilder() + builder.append("@" + originalTweet.user.screenName + " ") + + for (screenName in originalTweet.mentions) { + if (screenName != world.account.user.screenName) + builder.append("@$screenName ") + } + val text = builder.toString() + val selStart = originalTweet.user.screenName.length + 2 // "@" and " " + + world.postState.beginTransaction() + .clear() + .insertText(0, text) + .setInReplyTo(originalTweet) + .setSelection(selStart, text.length) + .commitWithOpen(activity as MainActivity) + } + R.id.button_status_detail_retweet -> { + val account = world.account + confirm({ + if (tweet.isRetweetedBy(account.userId)) { + Tweets.DestroyTask(account, tweet.getRetweetIdBy(account.userId)) + .onDone { t -> world.notify(R.string.notice_status_delete_succeeded) } + .onFail { e -> world.notifyError(R.string.notice_status_delete_failed) } + .execute() + dismiss() + } else { + TweetReactions.RetweetTask(account, tweet.id) + .onDone { x -> world.notify(R.string.notice_retweet_succeeded) } + .onFail { x -> world.notifyError(R.string.notice_retweet_failed) } + .execute() + } + }) + } + R.id.button_status_detail_favorite -> { + val account = world.account + if (tweet.isFavoritedBy(account.userId)) { + TweetReactions.UnfavoriteTask(account, tweet.id) + .onDone { x -> world.notify(R.string.notice_unfavorite_succeeded) } + .onFail { x -> world.notifyError(R.string.notice_unfavorite_failed) } + .execute() + } else { + TweetReactions.FavoriteTask(account, tweet.id) + .onDone { x -> world.notify(R.string.notice_favorite_succeeded) } + .onFail { x -> world.notifyError(R.string.notice_favorite_failed) } + .execute() + } + } + R.id.button_status_detail_delete -> { + confirm({ + Tweets.DestroyTask(world.account, tweet.originalTweet.id) + .onDone { t -> world.notify(R.string.notice_status_delete_succeeded) } + .onFail { e -> world.notifyError(R.string.notice_status_delete_failed) } + .execute() + dismiss() + }) + } + R.id.button_status_detail_menu -> { + val builder = AlertDialog.Builder(activity) + builder.setTitle("@" + tweet.user.screenName + ": " + tweet.text) + .setItems(R.array.status_commands) { dialog, which -> + when (which) { + 0 -> { + val text = String.format("@%s ", tweet.originalTweet.user.screenName) + world.postState.beginTransaction().insertText(0, text).moveCursor(text.length).commit() + world.notify(R.string.notice_add_to_reply) + } + 1 -> { + DialogHelper.showDialog(activity, TalkChainDialogFragment.newInstance(tweet)) + } + 2 -> IntentUtils.openUri(activity, tweet.originalTweet.twitterUrl) + 3 -> { + SystemServiceHelper.copyToClipboard(activity, "tweet text", tweet.originalTweet.text) + world.notify(R.string.notice_copy_clipboard) + } + 4 -> { + val statusURL = tweet.originalTweet.twitterUrl + SystemServiceHelper.copyToClipboard(activity, "tweet url", statusURL) + world.notify(R.string.notice_copy_clipboard) + } + else -> throw IllegalStateException() + } + } + val dialog = builder.create() + dialog.show() + } + else -> { + dismiss() + } + } + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val found = Tweet.fetch(arguments.getLong(KEY_STATUS_ID)) + if (found == null) { // trying to open deleted tweet? + world.notifyError(R.string.notice_error_show_status) + return DisposeDialog(activity) + } + tweet = found + + val view = activity.layoutInflater.inflate(R.layout.dialog_status_detail, null) + val bundle = UIObserverBundle() + view.tag = bundle + + val statusHeader = Partials.getTweetView(tweet, activity, view.findViewById(R.id.layout_status_header), true) + statusHeader.isClickable = false + + view.setBackgroundColor((statusHeader.background as ColorDrawable).color) + updateViewReactions(view) + updateViewButtons(view) + setupViewMenu(view) + + val weakView = WeakReference(view) + bundle.attach(tweet.originalTweet) { changes -> + val strongView = weakView.get() + if (strongView != null && activity != null) { + if (changes.contains(RBinding.REACTION_COUNT)) + updateViewReactions(strongView) + if (changes.contains(RBinding.FAVORITERS) || changes.contains(RBinding.RETWEETERS)) + updateViewButtons(strongView) + } + } + + val listView = view.findViewById(R.id.listview_status_detail_reply_to) as ListView + val adapter = TimelineAdapter(activity) + listView.adapter = adapter + + val replyDivider = view.findViewById(R.id.detail_dialog_divider_top) + + if (tweet.inReplyToStatusId != -1L) { + replyDivider.visibility = View.VISIBLE + listView.visibility = View.VISIBLE + Tweet.fetchTask(tweet.inReplyToStatusId, world.account) + .onDoneUI { replyTo -> + adapter.add(replyTo) + adapter.update() + } + .execute() + } else { + replyDivider.visibility = View.GONE + listView.visibility = View.GONE + } + + return AlertDialog.Builder(activity).setView(view).create() + } + + private fun updateViewReactions(view: View) { + val favCountIcon = view.findViewById(R.id.image_status_detail_fav_count) as ImageView + val favCountText = view.findViewById(R.id.textview_status_detail_fav_count) as TextView + if (tweet.favoriteCount > 0) { + favCountText.text = Integer.toString(tweet.favoriteCount) + favCountIcon.visibility = View.VISIBLE + favCountText.visibility = View.VISIBLE + } else { + favCountIcon.visibility = View.GONE + favCountText.visibility = View.GONE + } + + val rtCountIcon = view.findViewById(R.id.image_status_detail_rt_count) as ImageView + val rtCountText = view.findViewById(R.id.textview_status_detail_rt_count) as TextView + if (tweet.retweetCount > 0) { + rtCountText.text = Integer.toString(tweet.retweetCount) + rtCountIcon.visibility = View.VISIBLE + rtCountText.visibility = View.VISIBLE + } else { + rtCountIcon.visibility = View.GONE + rtCountText.visibility = View.GONE + } + } + + private fun updateViewButtons(view: View) { + val account = world.account + + //--- buttons + val reply = view.findViewById(R.id.button_status_detail_reply) as ImageButton + reply.setOnClickListener(this) + + val retweet = view.findViewById(R.id.button_status_detail_retweet) as ToggleableImageButton + retweet.setOnClickListener(this) + retweet.setState(tweet.isRetweetedBy(account.userId)) + + val favorite = view.findViewById(R.id.button_status_detail_favorite) as ToggleableImageButton + favorite.setOnClickListener(this) + favorite.setState(tweet.isFavoritedBy(account.userId)) + + val delete = view.findViewById(R.id.button_status_detail_delete) as ImageButton + delete.setOnClickListener(this) + delete.visibility = if (tweet.originalTweet.user === account.user) View.VISIBLE else View.GONE + + val menu = view.findViewById(R.id.button_status_detail_menu) as ImageButton + menu.setOnClickListener(this) + } + + private fun setupViewMenu(view: View) { + val divider = view.findViewById(R.id.detail_dialog_divider_bottom) + val listView = view.findViewById(R.id.listview_status_detail_menu) as ListView + val commands = commands + if (commands.size > 0) { + divider.visibility = View.VISIBLE + listView.visibility = View.VISIBLE + val adapter = object : CustomListAdapter() { + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { + var convertView = convertView + if (convertView == null) { + convertView = activity.layoutInflater.inflate(R.layout.menu_item_simple_text, null) + } + val textView = convertView!!.findViewById(R.id.list_item_textview) as TextView + textView.textSize = UserPreferenceHelper.instance.textSize.toFloat() + textView.text = getItem(position).text + return convertView + } + + override val list: List + get() = commands + } + adapter.update() + listView.adapter = adapter + listView.setOnItemClickListener { parent, view1, position, id -> + val command = parent.getItemAtPosition(position) as Command + command.execute() + } + } else { + divider.visibility = View.GONE + listView.visibility = View.GONE + } + } + + private fun confirm(onYes: () -> Unit) { + ConfirmDialogFragment.show(activity, getString(R.string.dialog_confirm_commands), onYes) + } + + private // Retweeter + // Mentions + // Array#uniq + // Hashtags + // URL + val commands: List + get() { + val activity = activity as MainActivity + val commands = ArrayList() + if (tweet.retweetedTweet != null && tweet.user !== tweet.retweetedTweet!!.user) + commands.add(CommandOpenUserDetail(activity, tweet.user.screenName)) + for (screenName in ArrayList(LinkedHashSet(tweet.mentions))) { + commands.add(CommandOpenUserDetail(activity, screenName)) + } + for (hashtag in tweet.hashtags) { + commands.add(CommandAddHashtag(activity, hashtag)) + } + for (url in tweet.urlsExpanded) { + commands.add(CommandOpenURL(activity, url)) + } + for (url in tweet.mediaUrls) { + commands.add(CommandOpenURL(activity, url)) + } + return commands + } + + companion object { + private val KEY_STATUS_ID = "status_id" + + fun newInstance(tweet: Tweet): StatusDetailDialogFragment { + val obj = StatusDetailDialogFragment() + val args = Bundle() + args.putLong(KEY_STATUS_ID, tweet.id) + obj.arguments = args + return obj + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/TalkChainDialogFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/TalkChainDialogFragment.java deleted file mode 100644 index 95bbac5c..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/dialog/TalkChainDialogFragment.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.view.dialog; - -import android.app.AlertDialog; -import android.app.Dialog; -import android.os.Bundle; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ListView; -import net.lacolaco.smileessence.Application; -import net.lacolaco.smileessence.R; -import net.lacolaco.smileessence.activity.MainActivity; -import net.lacolaco.smileessence.data.Account; -import net.lacolaco.smileessence.entity.Tweet; -import net.lacolaco.smileessence.twitter.task.Tweets; -import net.lacolaco.smileessence.view.Partials; -import net.lacolaco.smileessence.view.adapter.CustomListAdapter; - -import java.util.ArrayList; -import java.util.List; - -public class TalkChainDialogFragment extends StackableDialogFragment { - private static final String KEY_STATUS_ID = "KEY_STATUS_ID"; - - private long getStatusID() { - return getArguments().getLong(KEY_STATUS_ID); - } - - public void setStatusID(long id) { - Bundle bundle = new Bundle(); - bundle.putLong(KEY_STATUS_ID, id); - setArguments(bundle); - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - Account account = getWorld().getAccount(); - - View view = getActivity().getLayoutInflater().inflate(R.layout.dialog_talk_list, null); - ListView listView = (ListView) view.findViewById(R.id.listview_dialog_talk_list); - final List list = new ArrayList<>(); - final CustomListAdapter adapter = new CustomListAdapter() { - @Override - public View getView(int position, View convertView, ViewGroup parent) { - return Partials.getTweetView(getItem(position), getActivity(), convertView, true); - } - - @Override - protected List getList() { - return list; - } - }; - listView.setAdapter(adapter); - - new Tweets.GetTalkTask(account, getStatusID()).onProgressUI(tweet -> { - list.add(tweet); - adapter.updateForce(); - }).execute(); - - return new AlertDialog.Builder(getActivity()) - .setTitle(R.string.dialog_title_talk_chain) - .setView(view) - .setCancelable(true) - .create(); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/TalkChainDialogFragment.kt b/app/src/main/java/net/lacolaco/smileessence/view/dialog/TalkChainDialogFragment.kt new file mode 100644 index 00000000..1b39e50a --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/TalkChainDialogFragment.kt @@ -0,0 +1,81 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.dialog + +import android.app.AlertDialog +import android.app.Dialog +import android.os.Bundle +import android.view.View +import android.view.ViewGroup +import android.widget.ListView +import net.lacolaco.smileessence.R +import net.lacolaco.smileessence.entity.Tweet +import net.lacolaco.smileessence.twitter.task.Tweets +import net.lacolaco.smileessence.view.Partials +import net.lacolaco.smileessence.view.adapter.CustomListAdapter + +import java.util.ArrayList + +class TalkChainDialogFragment : StackableDialogFragment() { + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val account = world.account + + val view = activity.layoutInflater.inflate(R.layout.dialog_talk_list, null) + val listView = view.findViewById(R.id.listview_dialog_talk_list) as ListView + val list = ArrayList() + val adapter = object : CustomListAdapter() { + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { + return Partials.getTweetView(getItem(position), activity, convertView, true) + } + + override val list: List + get() = list + } + listView.adapter = adapter + + Tweets.GetTalkTask(account, arguments.getLong(KEY_STATUS_ID)).onProgressUI { tweet -> + list.add(tweet) + adapter.updateForce() + }.execute() + + return AlertDialog.Builder(activity) + .setTitle(R.string.dialog_title_talk_chain) + .setView(view) + .setCancelable(true) + .create() + } + + companion object { + private val KEY_STATUS_ID = "KEY_STATUS_ID" + + fun newInstance(tweet: Tweet): TalkChainDialogFragment { + val obj = TalkChainDialogFragment() + val bundle = Bundle() + bundle.putLong(KEY_STATUS_ID, tweet.originalTweet.id) + obj.arguments = bundle + return obj + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/UserDetailDialogFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/UserDetailDialogFragment.java deleted file mode 100644 index c8d62fa8..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/dialog/UserDetailDialogFragment.java +++ /dev/null @@ -1,423 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.view.dialog; - -import android.app.AlertDialog; -import android.app.Dialog; -import android.os.Bundle; -import android.text.Html; -import android.text.TextUtils; -import android.text.method.LinkMovementMethod; -import android.view.View; -import android.widget.AbsListView; -import android.widget.ListView; -import android.widget.TabHost; -import android.widget.TextView; -import com.android.volley.toolbox.NetworkImageView; -import com.handmark.pulltorefresh.library.PullToRefreshBase; -import com.handmark.pulltorefresh.library.PullToRefreshListView; -import net.lacolaco.smileessence.R; -import net.lacolaco.smileessence.activity.MainActivity; -import net.lacolaco.smileessence.data.Account; -import net.lacolaco.smileessence.data.ImageCache; -import net.lacolaco.smileessence.entity.RBinding; -import net.lacolaco.smileessence.entity.User; -import net.lacolaco.smileessence.twitter.task.Timelines; -import net.lacolaco.smileessence.twitter.task.Users; -import net.lacolaco.smileessence.util.IntentUtils; -import net.lacolaco.smileessence.util.UIHandler; -import net.lacolaco.smileessence.util.UIObserverBundle; -import net.lacolaco.smileessence.view.DialogHelper; -import net.lacolaco.smileessence.view.ThreeStateButton; -import net.lacolaco.smileessence.view.adapter.TimelineAdapter; - -public class UserDetailDialogFragment extends StackableDialogFragment implements View.OnClickListener, - PullToRefreshBase.OnRefreshListener2 { - - // ------------------------------ FIELDS ------------------------------ - - private static final String KEY_USER_ID = "userID"; - private TimelineAdapter adapter; - private TextView textViewScreenName; - private TextView textViewName; - private TextView textViewURL; - private TextView textViewLocate; - private TextView textViewFollowed; - private TextView textViewProtected; - private TextView textViewDescription; - private TextView textViewTweetCount; - private TextView textViewFriendCount; - private TextView textViewFollowerCount; - private TextView textViewFavoriteCount; - private NetworkImageView imageViewIcon; - private NetworkImageView imageViewHeader; - private ThreeStateButton buttonFollow; - private PullToRefreshListView listViewTimeline; - private TabHost tabHost; - private UIObserverBundle observerBundle; - private User user; - - // --------------------- GETTER / SETTER METHODS --------------------- - - public long getUserID() { - return getArguments().getLong(KEY_USER_ID); - } - - public void setUserID(long userID) { - Bundle args = new Bundle(); - args.putLong(KEY_USER_ID, userID); - setArguments(args); - } - - // ------------------------ INTERFACE METHODS ------------------------ - - - // --------------------- Interface OnClickListener --------------------- - - @Override - public void onClick(final View v) { - switch (v.getId()) { - case R.id.imageview_user_detail_menu: { - openUserMenu(); - break; - } - case R.id.imageview_user_detail_icon: { - IntentUtils.openUri(getActivity(), user.getProfileImageUrlOriginal()); - break; - } - case R.id.textview_user_detail_screenname: - case R.id.textview_user_detail_tweet_count: { - IntentUtils.openUri(getActivity(), user.getUserHomeURL()); - break; - } - case R.id.textview_user_detail_friend_count: { - IntentUtils.openUri(getActivity(), String.format("%s/following", user.getUserHomeURL())); - break; - } - case R.id.textview_user_detail_follower_count: { - IntentUtils.openUri(getActivity(), String.format("%s/followers", user.getUserHomeURL())); - break; - } - case R.id.textview_user_detail_favorite_count: { - IntentUtils.openUri(getActivity(), String.format("%s/favorites", user.getUserHomeURL())); - break; - } - case R.id.button_user_detail_follow: { - ConfirmDialogFragment.show(getActivity(), getString(R.string.dialog_confirm_commands), this::toggleFollowing); - break; - } - } - } - - // --------------------- Interface OnRefreshListener2 --------------------- - - @Override - public void onPullDownToRefresh(final PullToRefreshBase refreshView) { - Account currentAccount = getWorld().getAccount(); - new Timelines.UserTimelineTask(currentAccount, getUserID()) - .setCount(200) - .setSinceId(adapter.getTopID()) - .onFail(x -> getWorld().notifyError(R.string.notice_error_get_user_timeline)) - .onDoneUI(tweets -> { - adapter.addAll(tweets); - updateListView(refreshView.getRefreshableView(), adapter, true); - refreshView.onRefreshComplete(); - }) - .execute(); - } - - @Override - public void onPullUpToRefresh(final PullToRefreshBase refreshView) { - Account currentAccount = getWorld().getAccount(); - new Timelines.UserTimelineTask(currentAccount, getUserID()) - .setCount(200) - .setMaxId(adapter.getLastID() - 1) - .onFail(x -> getWorld().notifyError(R.string.notice_error_get_user_timeline)) - .onDoneUI(tweets -> { - adapter.addAll(tweets); - updateListView(refreshView.getRefreshableView(), adapter, false); - refreshView.onRefreshComplete(); - }) - .execute(); - } - - // ------------------------ OVERRIDE METHODS ------------------------ - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - user = User.fetch(getUserID()); - observerBundle = new UIObserverBundle(); - } - - @Override - public void onDestroy() { - super.onDestroy(); - observerBundle.detachAll(); - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - MainActivity activity = (MainActivity) getActivity(); - if (user == null) { - getWorld().notify(R.string.notice_error_show_user); - return new DisposeDialog(activity); - } - - View v = activity.getLayoutInflater().inflate(R.layout.dialog_user_detail, null); - View menu = v.findViewById(R.id.imageview_user_detail_menu); - menu.setOnClickListener(this); - textViewScreenName = (TextView) v.findViewById(R.id.textview_user_detail_screenname); - textViewScreenName.setOnClickListener(this); - textViewName = (TextView) v.findViewById(R.id.textview_user_detail_name); - textViewURL = (TextView) v.findViewById(R.id.textview_user_detail_url); - textViewLocate = (TextView) v.findViewById(R.id.textview_user_detail_locate); - textViewFollowed = (TextView) v.findViewById(R.id.textview_user_detail_followed); - textViewProtected = (TextView) v.findViewById(R.id.texttview_user_detail_protected); - textViewDescription = (TextView) v.findViewById(R.id.textview_user_detail_description); - textViewDescription.setMovementMethod(LinkMovementMethod.getInstance()); - textViewTweetCount = (TextView) v.findViewById(R.id.textview_user_detail_tweet_count); - textViewTweetCount.setOnClickListener(this); - textViewFriendCount = (TextView) v.findViewById(R.id.textview_user_detail_friend_count); - textViewFriendCount.setOnClickListener(this); - textViewFollowerCount = (TextView) v.findViewById(R.id.textview_user_detail_follower_count); - textViewFollowerCount.setOnClickListener(this); - textViewFavoriteCount = (TextView) v.findViewById(R.id.textview_user_detail_favorite_count); - textViewFavoriteCount.setOnClickListener(this); - imageViewIcon = (NetworkImageView) v.findViewById(R.id.imageview_user_detail_icon); - imageViewIcon.setOnClickListener(this); - imageViewHeader = (NetworkImageView) v.findViewById(R.id.imageview_user_detail_header); - buttonFollow = (ThreeStateButton) v.findViewById(R.id.button_user_detail_follow); - buttonFollow.setOnClickListener(this); - listViewTimeline = (PullToRefreshListView) v.findViewById(R.id.listview_user_detail_timeline); - listViewTimeline.setOnRefreshListener(this); - - tabHost = (TabHost) v.findViewById(android.R.id.tabhost); - tabHost.setup(); - TabHost.TabSpec tab1 = tabHost.newTabSpec("tab1").setContent(R.id.tab1).setIndicator(getString(R.string.user_detail_tab_info)); - tabHost.addTab(tab1); - TabHost.TabSpec tab2 = tabHost.newTabSpec("tab2").setContent(R.id.tab2).setIndicator(getString(R.string.user_detail_tab_timeline)); - tabHost.addTab(tab2); - tabHost.setCurrentTab(0); - - initUserData(); - - return new AlertDialog.Builder(activity) - .setView(v) - .setCancelable(true) - .create(); - } - - private void executeUserTimelineTask(final TimelineAdapter adapter) { - Account account = getWorld().getAccount(); - tabHost.getTabWidget().getChildTabViewAt(1).setVisibility(View.GONE); - new Timelines.UserTimelineTask(account, user.getId()) - .setCount(200) - .onFail(x -> getWorld().notifyError(R.string.notice_error_get_user_timeline)) - .onDoneUI(tweets -> { - adapter.addAll(tweets); - adapter.updateForce(); - tabHost.getTabWidget().getChildTabViewAt(1).setVisibility(View.VISIBLE); - }) - .execute(); - } - - private String getHtmlDescription() { - String description = user.getDescription(); - if (TextUtils.isEmpty(description)) { - return ""; - } - String html = description; - html = html.replaceAll("https?://[\\w/:%#$&?()~.=+-]+", "$0"); - html = html.replaceAll("@([a-zA-Z0-9_]+)", "$0"); - html = html.replaceAll("\r\n", "
"); - return html; - } - - private void updateUserDataBasic() { - textViewName.setText(user.getName()); - textViewScreenName.setText(user.getScreenName()); - textViewProtected.setVisibility(user.isProtected() ? View.VISIBLE : View.GONE); - imageViewIcon.setImageUrl(user.getProfileImageUrlOriginal(), ImageCache.getImageLoader()); - } - - private void updateUserDataDetail() { - if (TextUtils.isEmpty(user.getLocation())) { - textViewLocate.setVisibility(View.GONE); - } else { - textViewLocate.setText(user.getLocation()); - textViewLocate.setVisibility(View.VISIBLE); - } - if (TextUtils.isEmpty(user.getUrl())) { - textViewURL.setVisibility(View.GONE); - } else { - textViewURL.setText(user.getUrl()); - textViewURL.setVisibility(View.VISIBLE); - } - textViewDescription.setText(Html.fromHtml(getHtmlDescription())); - - textViewTweetCount.setText(String.valueOf(user.getStatusesCount())); - textViewFriendCount.setText(String.valueOf(user.getFriendsCount())); - textViewFollowerCount.setText(String.valueOf(user.getFollowersCount())); - textViewFavoriteCount.setText(String.valueOf(user.getFavoritesCount())); - - imageViewHeader.setImageUrl(user.getProfileBannerUrl(), ImageCache.getImageLoader()); - } - - private void initUserData() { - updateUserDataBasic(); - updateUserDataDetail(); - - MainActivity activity = (MainActivity) getActivity(); - adapter = new TimelineAdapter(activity); - listViewTimeline.setAdapter(adapter); - executeUserTimelineTask(adapter); - updateRelationship(); - - observerBundle.attach(user, changes -> { - if (getActivity() != null) { - if (changes.contains(RBinding.BASIC)) - updateUserDataBasic(); - if (changes.contains(RBinding.DETAIL)) - updateUserDataDetail(); - } - }); - } - - private void openUserMenu() { - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - builder.setTitle("@" + user.getScreenName()) - .setItems(R.array.user_commands, (dialog, which) -> { - // XXX - new UIHandler().postDelayed(() -> { - if (UserDetailDialogFragment.this.isAdded()) { - updateRelationship(); - } - }, 1000); - switch (which) { - case 0: - String text = String.format("@%s ", user.getScreenName()); - getWorld().getPostState().beginTransaction().insertText(0, text).moveCursor(text.length()).commit(); - getWorld().notify(R.string.notice_add_to_reply); - break; - case 1: - DialogHelper.showDialog(getActivity(), SendMessageDialogFragment.newInstance(user)); - break; - case 2: - ConfirmDialogFragment.show(getActivity(), getString(R.string.dialog_confirm_commands), () -> - new Users.BlockTask(getWorld().getAccount(), user.getId()) - .onDone(user -> getWorld().notify(R.string.notice_block_succeeded)) - .onFail(ex -> getWorld().notifyError(R.string.notice_block_failed)) - .execute()); - break; - case 3: - ConfirmDialogFragment.show(getActivity(), getString(R.string.dialog_confirm_commands), () -> - new Users.UnblockTask(getWorld().getAccount(), user.getId()) - .onDone(user -> getWorld().notify(R.string.notice_unblock_succeeded)) - .onFail(x -> getWorld().notifyError(R.string.notice_unblock_failed)) - .execute()); - break; - case 4: - ConfirmDialogFragment.show(getActivity(), getString(R.string.dialog_confirm_commands), () -> - new Users.ReportForSpamTask(getWorld().getAccount(), user.getId()) - .onDone(user -> getWorld().notify(R.string.notice_r4s_succeeded)) - .onFail(ex -> getWorld().notifyError(R.string.notice_r4s_failed)) - .execute()); - break; - case 5: - IntentUtils.openUri(getActivity(), user.getAclogTimelineURL()); - break; - default: - throw new IllegalStateException(); - } - }); - AlertDialog dialog = builder.create(); - dialog.show(); - } - - private void setFollowButtonState(boolean isFollowing) { - MainActivity mainActivity = (MainActivity) getActivity(); - if (mainActivity != null) { - buttonFollow.setState(isFollowing ? ThreeStateButton.STATE_ON : ThreeStateButton.STATE_OFF); - } - } - - private void toggleFollowing() { - Account account = getWorld().getAccount(); - Boolean isFollowing = buttonFollow.getState() == ThreeStateButton.STATE_ON; - buttonFollow.setState(ThreeStateButton.STATE_LOCKED); - if (isFollowing) { - new Users.UnfollowTask(account, user.getId()) - .onDoneUI(result -> { - getWorld().notify(R.string.notice_unfollow_succeeded); - updateRelationship(); - }) - .onFail(x -> - getWorld().notifyError(R.string.notice_unfollow_failed)) - .execute(); - } else { - new Users.FollowTask(account, user.getId()) - .onDoneUI(result -> { - getWorld().notify(R.string.notice_follow_succeeded); - updateRelationship(); - }) - .onFail(x -> getWorld().notifyError(R.string.notice_follow_failed)) - .execute(); - } - } - - private void updateListView(AbsListView absListView, TimelineAdapter adapter, boolean addedToTop) { - int before = adapter.getCount(); - adapter.notifyDataSetChanged(); // synchronized call (not adapter#updateForce()) - int after = adapter.getCount(); - int increments = after - before; - if (increments > 0) { - if (addedToTop) { - absListView.setSelection(increments + 1); - absListView.smoothScrollToPositionFromTop(increments, 0); - absListView.setSelection(increments); - } else { - absListView.smoothScrollToPositionFromTop(before, 0); - } - } - } - - private void updateRelationship() { - Account account = getWorld().getAccount(); - if (user == account.getUser()) { - textViewFollowed.setText(R.string.user_detail_followed_is_me); - buttonFollow.setVisibility(View.GONE); - } else { - buttonFollow.setState(ThreeStateButton.STATE_LOCKED); - textViewFollowed.setText(R.string.user_detail_loading); - new Users.ShowFriendshipTask(account, user.getId()).onDoneUI(relationship -> { - boolean isFollowing = relationship.isSourceFollowingTarget(); - boolean isFollowed = relationship.isSourceFollowedByTarget(); - setFollowButtonState(isFollowing); - textViewFollowed.setText(isFollowed ? R.string.user_detail_followed : R.string.user_detail_not_followed); - }).execute(); - } - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/UserDetailDialogFragment.kt b/app/src/main/java/net/lacolaco/smileessence/view/dialog/UserDetailDialogFragment.kt new file mode 100644 index 00000000..228a000a --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/UserDetailDialogFragment.kt @@ -0,0 +1,390 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.dialog + +import android.app.AlertDialog +import android.app.Dialog +import android.os.Bundle +import android.text.Html +import android.text.TextUtils +import android.text.method.LinkMovementMethod +import android.view.View +import android.widget.AbsListView +import android.widget.ListView +import android.widget.TabHost +import android.widget.TextView +import com.android.volley.toolbox.NetworkImageView +import com.handmark.pulltorefresh.library.PullToRefreshBase +import com.handmark.pulltorefresh.library.PullToRefreshListView +import net.lacolaco.smileessence.R +import net.lacolaco.smileessence.activity.MainActivity +import net.lacolaco.smileessence.data.ImageCache +import net.lacolaco.smileessence.entity.RBinding +import net.lacolaco.smileessence.entity.User +import net.lacolaco.smileessence.twitter.task.Timelines +import net.lacolaco.smileessence.twitter.task.Users +import net.lacolaco.smileessence.util.IntentUtils +import net.lacolaco.smileessence.util.UIHandler +import net.lacolaco.smileessence.util.UIObserverBundle +import net.lacolaco.smileessence.view.DialogHelper +import net.lacolaco.smileessence.view.ThreeStateButton +import net.lacolaco.smileessence.view.adapter.TimelineAdapter + +class UserDetailDialogFragment : StackableDialogFragment(), View.OnClickListener, PullToRefreshBase.OnRefreshListener2 { + private lateinit var adapter: TimelineAdapter + private lateinit var textViewScreenName: TextView + private lateinit var textViewName: TextView + private lateinit var textViewURL: TextView + private lateinit var textViewLocate: TextView + private lateinit var textViewFollowed: TextView + private lateinit var textViewProtected: TextView + private lateinit var textViewDescription: TextView + private lateinit var textViewTweetCount: TextView + private lateinit var textViewFriendCount: TextView + private lateinit var textViewFollowerCount: TextView + private lateinit var textViewFavoriteCount: TextView + private lateinit var imageViewIcon: NetworkImageView + private lateinit var imageViewHeader: NetworkImageView + private lateinit var buttonFollow: ThreeStateButton + private lateinit var listViewTimeline: PullToRefreshListView + private lateinit var tabHost: TabHost + private lateinit var observerBundle: UIObserverBundle + private lateinit var user: User + + override fun onClick(v: View) { + when (v.id) { + R.id.imageview_user_detail_menu -> { + openUserMenu() + } + R.id.imageview_user_detail_icon -> { + IntentUtils.openUri(activity, user.profileImageUrl!!) + } + R.id.textview_user_detail_screenname, R.id.textview_user_detail_tweet_count -> { + IntentUtils.openUri(activity, user.userHomeURL) + } + R.id.textview_user_detail_friend_count -> { + IntentUtils.openUri(activity, String.format("%s/following", user.userHomeURL)) + } + R.id.textview_user_detail_follower_count -> { + IntentUtils.openUri(activity, String.format("%s/followers", user.userHomeURL)) + } + R.id.textview_user_detail_favorite_count -> { + IntentUtils.openUri(activity, String.format("%s/favorites", user.userHomeURL)) + } + R.id.button_user_detail_follow -> { + ConfirmDialogFragment.show(activity, getString(R.string.dialog_confirm_commands)) { this.toggleFollowing() } + } + } + } + + // --------------------- Interface OnRefreshListener2 --------------------- + + override fun onPullDownToRefresh(refreshView: PullToRefreshBase) { + val currentAccount = world.account + Timelines.UserTimelineTask(currentAccount, user.id) + .setCount(200) + .setSinceId(adapter.topID) + .onFail { x -> world.notifyError(R.string.notice_error_get_user_timeline) } + .onDoneUI { tweets -> + adapter.addAll(tweets) + updateListView(refreshView.refreshableView, adapter, true) + refreshView.onRefreshComplete() + } + .execute() + } + + override fun onPullUpToRefresh(refreshView: PullToRefreshBase) { + val currentAccount = world.account + Timelines.UserTimelineTask(currentAccount, user.id) + .setCount(200) + .setMaxId(adapter.lastID - 1) + .onFail { x -> world.notifyError(R.string.notice_error_get_user_timeline) } + .onDoneUI { tweets -> + adapter.addAll(tweets) + updateListView(refreshView.refreshableView, adapter, false) + refreshView.onRefreshComplete() + } + .execute() + } + + // ------------------------ OVERRIDE METHODS ------------------------ + + override fun onCreate(savedInstanceState: Bundle) { + super.onCreate(savedInstanceState) + observerBundle = UIObserverBundle() + } + + override fun onDestroy() { + super.onDestroy() + observerBundle.detachAll() + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val activity = activity as MainActivity + val found = User.fetch(arguments.getLong(KEY_USER_ID)) + if (found == null) { + world.notify(R.string.notice_error_show_user) + return DisposeDialog(activity) + } + user = found + + val v = activity.layoutInflater.inflate(R.layout.dialog_user_detail, null) + val menu = v.findViewById(R.id.imageview_user_detail_menu) + menu.setOnClickListener(this) + textViewScreenName = v.findViewById(R.id.textview_user_detail_screenname) as TextView + textViewScreenName.setOnClickListener(this) + textViewName = v.findViewById(R.id.textview_user_detail_name) as TextView + textViewURL = v.findViewById(R.id.textview_user_detail_url) as TextView + textViewLocate = v.findViewById(R.id.textview_user_detail_locate) as TextView + textViewFollowed = v.findViewById(R.id.textview_user_detail_followed) as TextView + textViewProtected = v.findViewById(R.id.texttview_user_detail_protected) as TextView + textViewDescription = v.findViewById(R.id.textview_user_detail_description) as TextView + textViewDescription.movementMethod = LinkMovementMethod.getInstance() + textViewTweetCount = v.findViewById(R.id.textview_user_detail_tweet_count) as TextView + textViewTweetCount.setOnClickListener(this) + textViewFriendCount = v.findViewById(R.id.textview_user_detail_friend_count) as TextView + textViewFriendCount.setOnClickListener(this) + textViewFollowerCount = v.findViewById(R.id.textview_user_detail_follower_count) as TextView + textViewFollowerCount.setOnClickListener(this) + textViewFavoriteCount = v.findViewById(R.id.textview_user_detail_favorite_count) as TextView + textViewFavoriteCount.setOnClickListener(this) + imageViewIcon = v.findViewById(R.id.imageview_user_detail_icon) as NetworkImageView + imageViewIcon.setOnClickListener(this) + imageViewHeader = v.findViewById(R.id.imageview_user_detail_header) as NetworkImageView + buttonFollow = v.findViewById(R.id.button_user_detail_follow) as ThreeStateButton + buttonFollow.setOnClickListener(this) + listViewTimeline = v.findViewById(R.id.listview_user_detail_timeline) as PullToRefreshListView + listViewTimeline.setOnRefreshListener(this) + + tabHost = v.findViewById(android.R.id.tabhost) as TabHost + tabHost.setup() + val tab1 = tabHost.newTabSpec("tab1").setContent(R.id.tab1).setIndicator(getString(R.string.user_detail_tab_info)) + tabHost.addTab(tab1) + val tab2 = tabHost.newTabSpec("tab2").setContent(R.id.tab2).setIndicator(getString(R.string.user_detail_tab_timeline)) + tabHost.addTab(tab2) + tabHost.currentTab = 0 + + initUserData() + + return AlertDialog.Builder(activity) + .setView(v) + .setCancelable(true) + .create() + } + + private fun executeUserTimelineTask(adapter: TimelineAdapter) { + val account = world.account + tabHost.tabWidget.getChildTabViewAt(1).visibility = View.GONE + Timelines.UserTimelineTask(account, user.id) + .setCount(200) + .onFail { x -> world.notifyError(R.string.notice_error_get_user_timeline) } + .onDoneUI { tweets -> + adapter.addAll(tweets) + adapter.updateForce() + tabHost.tabWidget.getChildTabViewAt(1).visibility = View.VISIBLE + } + .execute() + } + + private val htmlDescription: String? + get() { + val description = user.description + if (TextUtils.isEmpty(description)) { + return "" + } + var html = description + html = html!!.replace("https?://[\\w/:%#$&?()~.=+-]+".toRegex(), "$0") + html = html.replace("@([a-zA-Z0-9_]+)".toRegex(), "$0") + html = html.replace("\r\n".toRegex(), "
") + return html + } + + private fun updateUserDataBasic() { + textViewName.text = user.name + textViewScreenName.text = user.screenName + textViewProtected.visibility = if (user.isProtected) View.VISIBLE else View.GONE + imageViewIcon.setImageUrl(user.profileImageUrl, ImageCache.getImageLoader()) + } + + private fun updateUserDataDetail() { + if (TextUtils.isEmpty(user.location)) { + textViewLocate.visibility = View.GONE + } else { + textViewLocate.text = user.location + textViewLocate.visibility = View.VISIBLE + } + if (TextUtils.isEmpty(user.url)) { + textViewURL.visibility = View.GONE + } else { + textViewURL.text = user.url + textViewURL.visibility = View.VISIBLE + } + textViewDescription.text = Html.fromHtml(htmlDescription) + + textViewTweetCount.text = user.statusesCount.toString() + textViewFriendCount.text = user.friendsCount.toString() + textViewFollowerCount.text = user.followersCount.toString() + textViewFavoriteCount.text = user.favoritesCount.toString() + + imageViewHeader.setImageUrl(user.profileBannerUrl, ImageCache.getImageLoader()) + } + + private fun initUserData() { + updateUserDataBasic() + updateUserDataDetail() + + val activity = activity as MainActivity + adapter = TimelineAdapter(activity) + listViewTimeline.setAdapter(adapter) + executeUserTimelineTask(adapter) + updateRelationship() + + observerBundle.attach(user) { changes -> + if (getActivity() != null) { + if (changes.contains(RBinding.BASIC)) + updateUserDataBasic() + if (changes.contains(RBinding.DETAIL)) + updateUserDataDetail() + } + } + } + + private fun openUserMenu() { + val builder = AlertDialog.Builder(activity) + builder.setTitle("@" + user.screenName) + .setItems(R.array.user_commands) { dialog, which -> + // XXX + UIHandler().postDelayed({ + if (this@UserDetailDialogFragment.isAdded) { + updateRelationship() + } + }, 1000) + when (which) { + 0 -> { + val text = String.format("@%s ", user.screenName) + world.postState.beginTransaction().insertText(0, text).moveCursor(text.length).commit() + world.notify(R.string.notice_add_to_reply) + } + 1 -> DialogHelper.showDialog(activity, SendMessageDialogFragment.newInstance(user)) + 2 -> ConfirmDialogFragment.show(activity, getString(R.string.dialog_confirm_commands)) { + Users.BlockTask(world.account, user.id) + .onDone { user -> world.notify(R.string.notice_block_succeeded) } + .onFail { ex -> world.notifyError(R.string.notice_block_failed) } + .execute() + } + 3 -> ConfirmDialogFragment.show(activity, getString(R.string.dialog_confirm_commands)) { + Users.UnblockTask(world.account, user.id) + .onDone { user -> world.notify(R.string.notice_unblock_succeeded) } + .onFail { x -> world.notifyError(R.string.notice_unblock_failed) } + .execute() + } + 4 -> ConfirmDialogFragment.show(activity, getString(R.string.dialog_confirm_commands)) { + Users.ReportForSpamTask(world.account, user.id) + .onDone { user -> world.notify(R.string.notice_r4s_succeeded) } + .onFail { ex -> world.notifyError(R.string.notice_r4s_failed) } + .execute() + } + 5 -> IntentUtils.openUri(activity, user.aclogTimelineURL) + else -> throw IllegalStateException() + } + } + val dialog = builder.create() + dialog.show() + } + + private fun setFollowButtonState(isFollowing: Boolean) { + if (activity != null) { + buttonFollow.state = if (isFollowing) ThreeStateButton.STATE_ON else ThreeStateButton.STATE_OFF + } + } + + private fun toggleFollowing() { + val account = world.account + val isFollowing = buttonFollow.state == ThreeStateButton.STATE_ON + buttonFollow.state = ThreeStateButton.STATE_LOCKED + if (isFollowing) { + Users.UnfollowTask(account, user.id) + .onDoneUI { result -> + world.notify(R.string.notice_unfollow_succeeded) + updateRelationship() + } + .onFail { x -> world.notifyError(R.string.notice_unfollow_failed) } + .execute() + } else { + Users.FollowTask(account, user.id) + .onDoneUI { result -> + world.notify(R.string.notice_follow_succeeded) + updateRelationship() + } + .onFail { x -> world.notifyError(R.string.notice_follow_failed) } + .execute() + } + } + + private fun updateListView(absListView: AbsListView, adapter: TimelineAdapter, addedToTop: Boolean) { + val before = adapter.count + adapter.notifyDataSetChanged() // synchronized call (not adapter#updateForce()) + val after = adapter.count + val increments = after - before + if (increments > 0) { + if (addedToTop) { + absListView.setSelection(increments + 1) + absListView.smoothScrollToPositionFromTop(increments, 0) + absListView.setSelection(increments) + } else { + absListView.smoothScrollToPositionFromTop(before, 0) + } + } + } + + private fun updateRelationship() { + val account = world.account + if (user === account.user) { + textViewFollowed.setText(R.string.user_detail_followed_is_me) + buttonFollow.visibility = View.GONE + } else { + buttonFollow.state = ThreeStateButton.STATE_LOCKED + textViewFollowed.setText(R.string.user_detail_loading) + Users.ShowFriendshipTask(account, user.id).onDoneUI { relationship -> + val isFollowing = relationship.isSourceFollowingTarget + val isFollowed = relationship.isSourceFollowedByTarget + setFollowButtonState(isFollowing) + textViewFollowed.setText(if (isFollowed) R.string.user_detail_followed else R.string.user_detail_not_followed) + }.execute() + } + } + + companion object { + private val KEY_USER_ID = "userID" + + fun newInstance(user: User): UserDetailDialogFragment { + val obj = UserDetailDialogFragment() + val bundle = Bundle() + bundle.putLong(KEY_USER_ID, user.id) + obj.arguments = bundle + return obj + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/listener/ListItemClickListener.java b/app/src/main/java/net/lacolaco/smileessence/view/listener/ListItemClickListener.java deleted file mode 100644 index 22d6180f..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/listener/ListItemClickListener.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.view.listener; - -import android.app.Activity; -import android.graphics.drawable.ColorDrawable; -import android.support.v4.content.ContextCompat; -import android.view.View; -import net.lacolaco.smileessence.R; -import net.lacolaco.smileessence.util.UIHandler; - -public class ListItemClickListener implements View.OnClickListener { - - // ------------------------------ FIELDS ------------------------------ - - private final Activity activity; - private final Runnable callback; - - // --------------------------- CONSTRUCTORS --------------------------- - - public ListItemClickListener(Activity activity, Runnable callback) { - this.activity = activity; - this.callback = callback; - } - - // ------------------------ INTERFACE METHODS ------------------------ - - - // --------------------- Interface OnClickListener --------------------- - - @Override - public void onClick(final View v) { - final int currentBgColor = ((ColorDrawable) v.getBackground()).getColor(); - v.setBackgroundColor(ContextCompat.getColor(activity, R.color.metro_blue)); - v.invalidate(); - new UIHandler().post(() -> { - v.setBackgroundColor(currentBgColor); - callback.run(); - }); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/listener/ListItemClickListener.kt b/app/src/main/java/net/lacolaco/smileessence/view/listener/ListItemClickListener.kt new file mode 100644 index 00000000..20404c63 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/listener/ListItemClickListener.kt @@ -0,0 +1,56 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.listener + +import android.app.Activity +import android.graphics.drawable.ColorDrawable +import android.support.v4.content.ContextCompat +import android.view.View +import net.lacolaco.smileessence.R +import net.lacolaco.smileessence.util.UIHandler + +class ListItemClickListener +// --------------------------- CONSTRUCTORS --------------------------- + +( + // ------------------------------ FIELDS ------------------------------ + + private val activity: Activity, private val callback: () -> Unit) : View.OnClickListener { + + // ------------------------ INTERFACE METHODS ------------------------ + + + // --------------------- Interface OnClickListener --------------------- + + override fun onClick(v: View) { + val currentBgColor = (v.background as ColorDrawable).color + v.setBackgroundColor(ContextCompat.getColor(activity, R.color.metro_blue)) + v.invalidate() + UIHandler().post { + v.setBackgroundColor(currentBgColor) + callback() + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/page/CustomListFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/page/CustomListFragment.java deleted file mode 100644 index 0dd24e67..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/page/CustomListFragment.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.view.page; - -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AbsListView; -import android.widget.ListView; -import com.handmark.pulltorefresh.library.PullToRefreshBase; -import com.handmark.pulltorefresh.library.PullToRefreshListView; -import net.lacolaco.smileessence.R; -import net.lacolaco.smileessence.World; -import net.lacolaco.smileessence.activity.MainActivity; -import net.lacolaco.smileessence.view.adapter.CustomListAdapter; - -public abstract class CustomListFragment extends PageFragment implements AbsListView.OnScrollListener, - PullToRefreshBase.OnRefreshListener2 { - - // --------------------- GETTER / SETTER METHODS --------------------- - - protected PullToRefreshBase.Mode getRefreshMode() { - return PullToRefreshBase.Mode.DISABLED; - } - - // ------------------------ INTERFACE METHODS ------------------------ - - - // --------------------- Interface OnRefreshListener2 --------------------- - - @Override - public void onPullDownToRefresh(PullToRefreshBase refreshView) { - } - - @Override - public void onPullUpToRefresh(PullToRefreshBase refreshView) { - } - - // --------------------- Interface OnScrollListener --------------------- - - @Override - public void onScrollStateChanged(AbsListView absListView, int scrollState) { - T adapter = getAdapter(); - if (scrollState != SCROLL_STATE_TOUCH_SCROLL && - absListView.getFirstVisiblePosition() == 0 && (absListView.getChildAt(0) == null || absListView.getChildAt(0).getTop() == 0)) { - adapter.setNotifiable(true); - updateListViewWithNotice(absListView, true); - } else { - adapter.setNotifiable(false); - } - } - - @Override - public void onScroll(AbsListView absListView, int i, int i2, int i3) { - } - - // ------------------------ OVERRIDE METHODS ------------------------ - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View page = inflater.inflate(R.layout.fragment_list, container, false); - PullToRefreshListView listView = getListView(page); - listView.setAdapter(getAdapter()); - listView.setOnScrollListener(this); - listView.setOnRefreshListener(this); - listView.setMode(getRefreshMode()); - return page; - } - - protected PullToRefreshListView getListView(View page) { - return (PullToRefreshListView) page.findViewById(R.id.fragment_list_listview); - } - - protected void updateListViewWithNotice(AbsListView absListView, boolean addedToTop) { - T adapter = getAdapter(); - int before = adapter.getCount(); - adapter.notifyDataSetChanged(); // synchronized call (not adapter#updateForce()) - int after = adapter.getCount(); - int increments = after - before; - if (increments > 0) { - if (addedToTop) { - absListView.setSelection(increments + 1); - absListView.smoothScrollToPositionFromTop(increments, 0); - absListView.setSelection(increments); - } else { - absListView.smoothScrollToPositionFromTop(before, 0); - } - - if (increments > 1) { - adapter.setNotifiable(false); - } - } - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/page/CustomListFragment.kt b/app/src/main/java/net/lacolaco/smileessence/view/page/CustomListFragment.kt new file mode 100644 index 00000000..d8536263 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/page/CustomListFragment.kt @@ -0,0 +1,107 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.page + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.AbsListView +import android.widget.ListView +import com.handmark.pulltorefresh.library.PullToRefreshBase +import com.handmark.pulltorefresh.library.PullToRefreshListView +import net.lacolaco.smileessence.R +import net.lacolaco.smileessence.World +import net.lacolaco.smileessence.activity.MainActivity +import net.lacolaco.smileessence.view.adapter.CustomListAdapter + +abstract class CustomListFragment> : PageFragment(), AbsListView.OnScrollListener, PullToRefreshBase.OnRefreshListener2 { + + // --------------------- GETTER / SETTER METHODS --------------------- + + protected open val refreshMode: PullToRefreshBase.Mode + get() = PullToRefreshBase.Mode.DISABLED + + // ------------------------ INTERFACE METHODS ------------------------ + + + // --------------------- Interface OnRefreshListener2 --------------------- + + override fun onPullDownToRefresh(refreshView: PullToRefreshBase) {} + + override fun onPullUpToRefresh(refreshView: PullToRefreshBase) {} + + // --------------------- Interface OnScrollListener --------------------- + + override fun onScrollStateChanged(absListView: AbsListView, scrollState: Int) { + val adapter = adapter + if (scrollState != AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL && + absListView.firstVisiblePosition == 0 && (absListView.getChildAt(0) == null || absListView.getChildAt(0).top == 0)) { + adapter.setNotifiable(true) + updateListViewWithNotice(absListView, true) + } else { + adapter.setNotifiable(false) + } + } + + override fun onScroll(absListView: AbsListView, i: Int, i2: Int, i3: Int) {} + + // ------------------------ OVERRIDE METHODS ------------------------ + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup, savedInstanceState: Bundle?): View { + val page = inflater.inflate(R.layout.fragment_list, container, false) + val listView = getListView(page) + listView.setAdapter(adapter) + listView.setOnScrollListener(this) + listView.setOnRefreshListener(this) + listView.mode = refreshMode + return page + } + + protected open fun getListView(page: View): PullToRefreshListView { + return page.findViewById(R.id.fragment_list_listview) as PullToRefreshListView + } + + protected fun updateListViewWithNotice(absListView: AbsListView, addedToTop: Boolean) { + val adapter = adapter + val before = adapter.count + adapter.notifyDataSetChanged() // synchronized call (not adapter#updateForce()) + val after = adapter.count + val increments = after - before + if (increments > 0) { + if (addedToTop) { + absListView.setSelection(increments + 1) + absListView.smoothScrollToPositionFromTop(increments, 0) + absListView.setSelection(increments) + } else { + absListView.smoothScrollToPositionFromTop(before, 0) + } + + if (increments > 1) { + adapter.setNotifiable(false) + } + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/page/HistoryFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/page/HistoryFragment.java deleted file mode 100644 index 5f04114e..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/page/HistoryFragment.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.view.page; - -import android.os.Bundle; -import com.handmark.pulltorefresh.library.PullToRefreshBase; -import net.lacolaco.smileessence.World; -import net.lacolaco.smileessence.view.adapter.EventListAdapter; - -public class HistoryFragment extends CustomListFragment { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - World world = getWorld(); - final EventListAdapter adapter = new EventListAdapter(world, getActivity()); - setAdapter(adapter); - world.addEventNotifier(this, () -> adapter.update()); // XXX - } - - @Override - public void refresh() { - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/page/HistoryFragment.kt b/app/src/main/java/net/lacolaco/smileessence/view/page/HistoryFragment.kt new file mode 100644 index 00000000..70cae02f --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/page/HistoryFragment.kt @@ -0,0 +1,41 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.page + +import android.os.Bundle +import com.handmark.pulltorefresh.library.PullToRefreshBase +import net.lacolaco.smileessence.World +import net.lacolaco.smileessence.view.adapter.EventListAdapter + +class HistoryFragment : CustomListFragment() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + adapter = EventListAdapter(world, activity) + world.addEventNotifier(this) { adapter.update() } // XXX + } + + override fun refresh() {} +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/page/HomeFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/page/HomeFragment.java deleted file mode 100644 index e00f69c6..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/page/HomeFragment.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.view.page; - -import android.os.Bundle; -import android.widget.ListView; -import com.handmark.pulltorefresh.library.PullToRefreshBase; -import net.lacolaco.smileessence.Application; -import net.lacolaco.smileessence.R; -import net.lacolaco.smileessence.activity.MainActivity; -import net.lacolaco.smileessence.entity.Tweet; -import net.lacolaco.smileessence.logging.Logger; -import net.lacolaco.smileessence.twitter.task.TimelineTask; -import net.lacolaco.smileessence.twitter.task.Timelines; -import net.lacolaco.smileessence.util.UIHandler; -import net.lacolaco.smileessence.view.adapter.TimelineAdapter; - -public class HomeFragment extends CustomListFragment { - @Override - protected PullToRefreshBase.Mode getRefreshMode() { - return PullToRefreshBase.Mode.BOTH; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - TimelineAdapter adapter = new TimelineAdapter(getActivity()); - setAdapter(adapter); - - getWorld().addTimeline(this, tweet -> { - adapter.add(tweet); - adapter.update(); - }); - - refresh(); - } - - @Override - public void refresh() { - runRefreshTask(new Timelines.HomeTimelineTask(getWorld().getAccount()), () -> getAdapter().updateForce()); - } - - // --------------------- Interface OnRefreshListener2 --------------------- - - @Override - public void onPullDownToRefresh(final PullToRefreshBase refreshView) { - if (getWorld().isStreaming()) { - new UIHandler().post(() -> { - updateListViewWithNotice(refreshView.getRefreshableView(), true); - refreshView.onRefreshComplete(); - }); - } else { - runRefreshTask( - new Timelines.HomeTimelineTask(getWorld().getAccount()) - .setSinceId(getAdapter().getTopID()), - () -> { - updateListViewWithNotice(refreshView.getRefreshableView(), true); - refreshView.onRefreshComplete(); - }); - } - } - - @Override - public void onPullUpToRefresh(final PullToRefreshBase refreshView) { - runRefreshTask( - new Timelines.HomeTimelineTask(getWorld().getAccount()) - .setMaxId(getAdapter().getLastID() - 1), - () -> { - updateListViewWithNotice(refreshView.getRefreshableView(), false); - refreshView.onRefreshComplete(); - }); - } - - private void runRefreshTask(TimelineTask task, Runnable onFinish) { - task - .setCount(200) - .onFail(e -> getWorld().notifyError(R.string.notice_error_get_home)) - .onDoneUI(tweets -> getWorld().addTweetAll(tweets)) - .onFinishUI(onFinish) - .execute(); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/page/HomeFragment.kt b/app/src/main/java/net/lacolaco/smileessence/view/page/HomeFragment.kt new file mode 100644 index 00000000..a9bd8fe4 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/page/HomeFragment.kt @@ -0,0 +1,97 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.page + +import android.os.Bundle +import android.widget.ListView +import com.handmark.pulltorefresh.library.PullToRefreshBase +import net.lacolaco.smileessence.Application +import net.lacolaco.smileessence.R +import net.lacolaco.smileessence.activity.MainActivity +import net.lacolaco.smileessence.entity.Tweet +import net.lacolaco.smileessence.logging.Logger +import net.lacolaco.smileessence.twitter.task.TimelineTask +import net.lacolaco.smileessence.twitter.task.Timelines +import net.lacolaco.smileessence.util.UIHandler +import net.lacolaco.smileessence.view.adapter.TimelineAdapter + +class HomeFragment : CustomListFragment() { + override val refreshMode: PullToRefreshBase.Mode + get() = PullToRefreshBase.Mode.BOTH + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + adapter = TimelineAdapter(activity) + + world.addTimeline(this) { tweet -> + adapter.add(tweet) + adapter.update() + } + + refresh() + } + + override fun refresh() { + runRefreshTask(Timelines.HomeTimelineTask(world.account), { adapter.updateForce() }) + } + + // --------------------- Interface OnRefreshListener2 --------------------- + + override fun onPullDownToRefresh(refreshView: PullToRefreshBase) { + if (world.isStreaming) { + UIHandler().post { + updateListViewWithNotice(refreshView.refreshableView, true) + refreshView.onRefreshComplete() + } + } else { + runRefreshTask( + Timelines.HomeTimelineTask(world.account) + .setSinceId(adapter.topID), + { + updateListViewWithNotice(refreshView.refreshableView, true) + refreshView.onRefreshComplete() + }) + } + } + + override fun onPullUpToRefresh(refreshView: PullToRefreshBase) { + runRefreshTask( + Timelines.HomeTimelineTask(world.account) + .setMaxId(adapter.lastID - 1), + { + updateListViewWithNotice(refreshView.refreshableView, false) + refreshView.onRefreshComplete() + }) + } + + private fun runRefreshTask(task: TimelineTask, onFinish: () -> Unit) { + task + .setCount(200) + .onFail { e -> world.notifyError(R.string.notice_error_get_home) } + .onDoneUI { tweets -> world.addTweetAll(tweets) } + .onFinishUI(onFinish) + .execute() + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/page/MentionsFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/page/MentionsFragment.java deleted file mode 100644 index 21ae1169..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/page/MentionsFragment.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.view.page; - -import android.os.Bundle; -import android.widget.ListView; -import com.handmark.pulltorefresh.library.PullToRefreshBase; -import net.lacolaco.smileessence.Application; -import net.lacolaco.smileessence.R; -import net.lacolaco.smileessence.data.ExtractionWord; -import net.lacolaco.smileessence.entity.Tweet; -import net.lacolaco.smileessence.entity.User; -import net.lacolaco.smileessence.twitter.task.TimelineTask; -import net.lacolaco.smileessence.twitter.task.Timelines; -import net.lacolaco.smileessence.view.adapter.TimelineAdapter; - -public class MentionsFragment extends CustomListFragment { - - // --------------------- GETTER / SETTER METHODS --------------------- - - @Override - protected PullToRefreshBase.Mode getRefreshMode() { - return PullToRefreshBase.Mode.BOTH; - } - - // ------------------------ INTERFACE METHODS ------------------------ - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - final TimelineAdapter adapter = new TimelineAdapter(getActivity()); - setAdapter(adapter); - - // Prevent calling getWorld() on null - final User self = getWorld().getAccount().getUser(); - getWorld().addTimeline(this, tweet -> { - if (tweet.getMentions().contains(self.getScreenName())) { - adapter.add(tweet); - adapter.update(); - } else { - for (ExtractionWord word : ExtractionWord.cached()) { - if (word.getPattern().matcher(tweet.getOriginalTweet().getText()).find()) { - adapter.add(tweet); - adapter.update(); - } - } - } - }); - - refresh(); - } - - @Override - public void refresh() { - runRefreshTask(new Timelines.MentionsTimelineTask(getWorld().getAccount()), () -> getAdapter().updateForce()); - } - - // --------------------- Interface OnRefreshListener2 --------------------- - - @Override - public void onPullDownToRefresh(final PullToRefreshBase refreshView) { - runRefreshTask( - new Timelines.MentionsTimelineTask(getWorld().getAccount()) - .setSinceId(getAdapter().getTopID()), - () -> { - updateListViewWithNotice(refreshView.getRefreshableView(), true); - refreshView.onRefreshComplete(); - }); - } - - @Override - public void onPullUpToRefresh(final PullToRefreshBase refreshView) { - runRefreshTask( - new Timelines.MentionsTimelineTask(getWorld().getAccount()) - .setMaxId(getAdapter().getLastID() - 1), - () -> { - updateListViewWithNotice(refreshView.getRefreshableView(), false); - refreshView.onRefreshComplete(); - }); - } - - private void runRefreshTask(TimelineTask task, Runnable onFinish) { - task - .setCount(200) - .onFail(x -> getWorld().notifyError(R.string.notice_error_get_mentions)) - .onDoneUI(tweets -> getWorld().addTweetAll(tweets)) - .onFinishUI(onFinish) - .execute(); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/page/MentionsFragment.kt b/app/src/main/java/net/lacolaco/smileessence/view/page/MentionsFragment.kt new file mode 100644 index 00000000..d8442ac7 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/page/MentionsFragment.kt @@ -0,0 +1,102 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.page + +import android.os.Bundle +import android.widget.ListView +import com.handmark.pulltorefresh.library.PullToRefreshBase +import net.lacolaco.smileessence.Application +import net.lacolaco.smileessence.R +import net.lacolaco.smileessence.data.ExtractionWord +import net.lacolaco.smileessence.entity.Tweet +import net.lacolaco.smileessence.entity.User +import net.lacolaco.smileessence.twitter.task.TimelineTask +import net.lacolaco.smileessence.twitter.task.Timelines +import net.lacolaco.smileessence.view.adapter.TimelineAdapter + +class MentionsFragment : CustomListFragment() { + override val refreshMode: PullToRefreshBase.Mode + get() = PullToRefreshBase.Mode.BOTH + + // ------------------------ INTERFACE METHODS ------------------------ + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + adapter = TimelineAdapter(activity) + + // Prevent calling getWorld() on null + val self = world.account.user + world.addTimeline(this) { tweet -> + if (tweet.mentions.contains(self.screenName)) { + adapter.add(tweet) + adapter.update() + } else { + for (word in ExtractionWord.cached()) { + if (word.pattern.matcher(tweet.originalTweet.text).find()) { + adapter.add(tweet) + adapter.update() + } + } + } + } + + refresh() + } + + override fun refresh() { + runRefreshTask(Timelines.MentionsTimelineTask(world.account), { adapter.updateForce() }) + } + + // --------------------- Interface OnRefreshListener2 --------------------- + + override fun onPullDownToRefresh(refreshView: PullToRefreshBase) { + runRefreshTask( + Timelines.MentionsTimelineTask(world.account) + .setSinceId(adapter.topID), + { + updateListViewWithNotice(refreshView.refreshableView, true) + refreshView.onRefreshComplete() + }) + } + + override fun onPullUpToRefresh(refreshView: PullToRefreshBase) { + runRefreshTask( + Timelines.MentionsTimelineTask(world.account) + .setMaxId(adapter.lastID - 1), + { + updateListViewWithNotice(refreshView.refreshableView, false) + refreshView.onRefreshComplete() + }) + } + + private fun runRefreshTask(task: TimelineTask, onFinish: () -> Unit) { + task + .setCount(200) + .onFail { x -> world.notifyError(R.string.notice_error_get_mentions) } + .onDoneUI { tweets -> world.addTweetAll(tweets) } + .onFinishUI(onFinish) + .execute() + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/page/MessagesFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/page/MessagesFragment.java deleted file mode 100644 index 291f4cfc..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/page/MessagesFragment.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.view.page; - -import android.os.Bundle; -import android.widget.ListView; -import com.handmark.pulltorefresh.library.PullToRefreshBase; -import net.lacolaco.smileessence.Application; -import net.lacolaco.smileessence.R; -import net.lacolaco.smileessence.entity.DirectMessage; -import net.lacolaco.smileessence.twitter.task.Messages; -import net.lacolaco.smileessence.twitter.task.TimelineTask; -import net.lacolaco.smileessence.view.adapter.MessageListAdapter; - -public class MessagesFragment extends CustomListFragment { - @Override - protected PullToRefreshBase.Mode getRefreshMode() { - return PullToRefreshBase.Mode.BOTH; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - MessageListAdapter adapter = new MessageListAdapter(getActivity()); - setAdapter(adapter); - - getWorld().addDirectMessageTimeline(this, message -> { - adapter.add(message); - adapter.update(); - }); - - refresh(); - } - - @Override - public void refresh() { - runRefreshTask(new Messages.GetAllReceived(getWorld().getAccount()), () -> getAdapter().updateForce()); - runRefreshTask(new Messages.GetAllSent(getWorld().getAccount()), () -> getAdapter().updateForce()); - } - - @Override - public void onPullDownToRefresh(final PullToRefreshBase refreshView) { - runRefreshTask( - new Messages.GetAllReceived(getWorld().getAccount()) - .setSinceId(getAdapter().getTopID()), - () -> { - updateListViewWithNotice(refreshView.getRefreshableView(), true); - refreshView.onRefreshComplete(); - }); // TODO: sent? - } - - @Override - public void onPullUpToRefresh(final PullToRefreshBase refreshView) { - runRefreshTask( - new Messages.GetAllReceived(getWorld().getAccount()) - .setMaxId(getAdapter().getLastID() - 1), - () -> { - updateListViewWithNotice(refreshView.getRefreshableView(), false); - refreshView.onRefreshComplete(); - }); // TODO: sent? - } - - private void runRefreshTask(TimelineTask task, Runnable onFinish) { - task - .setCount(200) - .onFail(x -> getWorld().notifyError(R.string.notice_error_get_messages)) - .onDoneUI(messages -> { - for (DirectMessage message : messages) { - getWorld().addDirectMessage(message); - } - }) - .onFinishUI(onFinish) - .execute(); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/page/MessagesFragment.kt b/app/src/main/java/net/lacolaco/smileessence/view/page/MessagesFragment.kt new file mode 100644 index 00000000..ea756d09 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/page/MessagesFragment.kt @@ -0,0 +1,90 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.page + +import android.os.Bundle +import android.widget.ListView +import com.handmark.pulltorefresh.library.PullToRefreshBase +import net.lacolaco.smileessence.Application +import net.lacolaco.smileessence.R +import net.lacolaco.smileessence.entity.DirectMessage +import net.lacolaco.smileessence.twitter.task.Messages +import net.lacolaco.smileessence.twitter.task.TimelineTask +import net.lacolaco.smileessence.view.adapter.MessageListAdapter + +class MessagesFragment : CustomListFragment() { + override val refreshMode: PullToRefreshBase.Mode + get() = PullToRefreshBase.Mode.BOTH + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + adapter = MessageListAdapter(activity) + + world.addDirectMessageTimeline(this) { message -> + adapter.add(message) + adapter.update() + } + + refresh() + } + + override fun refresh() { + runRefreshTask(Messages.GetAllReceived(world.account), { adapter.updateForce() }) + runRefreshTask(Messages.GetAllSent(world.account), { adapter.updateForce() }) + } + + override fun onPullDownToRefresh(refreshView: PullToRefreshBase) { + runRefreshTask( + Messages.GetAllReceived(world.account) + .setSinceId(adapter.topID), + { + updateListViewWithNotice(refreshView.refreshableView, true) + refreshView.onRefreshComplete() + }) // TODO: sent? + } + + override fun onPullUpToRefresh(refreshView: PullToRefreshBase) { + runRefreshTask( + Messages.GetAllReceived(world.account) + .setMaxId(adapter.lastID - 1), + { + updateListViewWithNotice(refreshView.refreshableView, false) + refreshView.onRefreshComplete() + }) // TODO: sent? + } + + private fun runRefreshTask(task: TimelineTask, onFinish: () -> Unit) { + task + .setCount(200) + .onFail { x -> world.notifyError(R.string.notice_error_get_messages) } + .onDoneUI { messages -> + for (message in messages) { + world.addDirectMessage(message) + } + } + .onFinishUI(onFinish) + .execute() + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/page/PageFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/page/PageFragment.java deleted file mode 100644 index c1299298..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/page/PageFragment.java +++ /dev/null @@ -1,32 +0,0 @@ -package net.lacolaco.smileessence.view.page; - -import android.app.Fragment; -import android.os.Bundle; -import android.widget.Adapter; -import net.lacolaco.smileessence.Application; -import net.lacolaco.smileessence.World; -import net.lacolaco.smileessence.activity.MainActivity; - -public abstract class PageFragment extends Fragment { - public static final String KEY_USER_ID = "KEY_USER_ID"; - private T adapter; - private World world; - - protected final T getAdapter() { - if (adapter == null) throw new IllegalStateException("adapter is not initialized"); - return adapter; - } - - protected final void setAdapter(T _adapter) { - adapter = _adapter; - } - - public abstract void refresh(); - - protected final World getWorld() { - if (world == null) { - world = Application.getWorld(getArguments().getLong(KEY_USER_ID)); - } - return world; - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/page/PageFragment.kt b/app/src/main/java/net/lacolaco/smileessence/view/page/PageFragment.kt new file mode 100644 index 00000000..596f4107 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/page/PageFragment.kt @@ -0,0 +1,25 @@ +package net.lacolaco.smileessence.view.page + +import android.app.Fragment +import android.os.Bundle +import android.widget.Adapter +import net.lacolaco.smileessence.Application +import net.lacolaco.smileessence.World +import net.lacolaco.smileessence.activity.MainActivity + +abstract class PageFragment : Fragment() { + private var _adapter: T? = null + protected var adapter: T + get() = _adapter ?: throw IllegalStateException("adapter is not initialized") + set(value) { _adapter = value } + + protected val world: World by lazy { + Application.getWorld(arguments.getLong(KEY_USER_ID)) + } + + abstract fun refresh() + + companion object { + val KEY_USER_ID = "KEY_USER_ID" + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/page/PostFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/page/PostFragment.java deleted file mode 100644 index c8426383..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/page/PostFragment.java +++ /dev/null @@ -1,334 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.view.page; - -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.content.ContextCompat; -import android.text.Editable; -import android.text.Spannable; -import android.text.TextUtils; -import android.text.TextWatcher; -import android.text.method.ArrowKeyMovementMethod; -import android.view.*; -import android.widget.*; -import com.twitter.Validator; -import net.lacolaco.smileessence.R; -import net.lacolaco.smileessence.World; -import net.lacolaco.smileessence.activity.MainActivity; -import net.lacolaco.smileessence.data.PostState; -import net.lacolaco.smileessence.entity.Tweet; -import net.lacolaco.smileessence.logging.Logger; -import net.lacolaco.smileessence.preference.UserPreferenceHelper; -import net.lacolaco.smileessence.twitter.task.Tweets; -import net.lacolaco.smileessence.util.BitmapThumbnailTask; -import net.lacolaco.smileessence.util.IntentUtils; -import net.lacolaco.smileessence.util.SystemServiceHelper; -import net.lacolaco.smileessence.util.UIHandler; -import net.lacolaco.smileessence.view.Partials; - -import java.io.File; - -public class PostFragment extends PageFragment implements TextWatcher, View.OnFocusChangeListener, View.OnClickListener, - PostState.OnPostStateChangeListener { - // ------------------------------ FIELDS ------------------------------ - - private EditText editText; - private TextView textViewCount; - private Button buttonTweet; - private ViewGroup viewGroupReply; - private ViewGroup viewGroupMedia; - - @Override - public void refresh() { - } - - // --------------------- Interface OnClickListener --------------------- - - @Override - public void onClick(View v) { - switch (v.getId()) { - case R.id.button_post_delete: { - deletePost(); - break; - } - case R.id.button_post_media: { - setImage(); - break; - } - case R.id.button_post_tweet: { - submitPost(); - break; - } - case R.id.button_post_reply_delete: { - deleteReply(); - break; - } - case R.id.button_post_media_delete: { - removeImage(); - break; - } - case R.id.image_post_media: { - displayImage(); - break; - } - } - } - - // --------------------- Interface OnFocusChangeListener --------------------- - - @Override - public void onFocusChange(View v, boolean hasFocus) { - if (hasFocus) { - SystemServiceHelper.showIM(getActivity(), editText); - } else { - SystemServiceHelper.hideIM(getActivity(), editText); - } - } - - // --------------------- Interface OnPostStateChangeListener --------------------- - - - @Override - public void onPostStateChange(final PostState postState) { - Logger.debug("onPostStateChange"); - final MainActivity activity = (MainActivity) getActivity(); - if (editText != null) { - final int start = postState.getSelectionStart(); - final int end = postState.getSelectionEnd(); - editText.removeTextChangedListener(this); - editText.setTextKeepState(postState.getText()); - editText.addTextChangedListener(this); - updateTextCount(editText.getText()); - new UIHandler().postAtFrontOfQueue(() -> editText.setSelection(start, end)); - } - if (viewGroupReply != null) { - if (postState.getInReplyTo() != null) { - viewGroupReply.setVisibility(View.VISIBLE); - ImageButton imageButtonDeleteReply = (ImageButton) viewGroupReply.findViewById(R.id.button_post_reply_delete); - imageButtonDeleteReply.setOnClickListener(this); - - Tweet tweet = postState.getInReplyTo(); - View header = viewGroupReply.findViewById(R.id.layout_post_reply_status); - header = Partials.getTweetView(tweet, activity, header, true); - header.setBackgroundColor(ContextCompat.getColor(getActivity(), R.color.transparent)); - header.setClickable(false); - } else { - viewGroupReply.setVisibility(View.GONE); - } - } - if (viewGroupMedia != null) { - ImageView imageViewMedia = (ImageView) viewGroupMedia.findViewById(R.id.image_post_media); - if (TextUtils.isEmpty(postState.getMediaFilePath())) { - viewGroupMedia.setVisibility(View.GONE); - } else { - viewGroupMedia.setVisibility(View.VISIBLE); - - } - new BitmapThumbnailTask(postState.getMediaFilePath(), imageViewMedia).execute(); - } - } - - // --------------------- Interface 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) { - updateTextCount(s); - } - - private void updateTextCount(CharSequence s) { - Validator validator = new Validator(); - int remainingCount = 140 - validator.getTweetLength(s.toString()); - if (!TextUtils.isEmpty(getWorld().getPostState().getMediaFilePath())) { - remainingCount -= validator.getShortUrlLength(); - } - textViewCount.setText(String.valueOf(remainingCount)); - if (remainingCount == 140 || remainingCount < 0) { - textViewCount.setTextColor(ContextCompat.getColor(getActivity(), R.color.red)); - } else { - textViewCount.setTextAppearance(getActivity(), android.R.style.TextAppearance_Widget_TextView); - } - setStateFromView(); - } - - @Override - public void afterTextChanged(Editable s) { - } - - // ------------------------ OVERRIDE METHODS ------------------------ - - @Override - public void onCreate(Bundle savedInstanceState) { - Logger.debug("onCreate"); - super.onCreate(savedInstanceState); - setHasOptionsMenu(true); - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - super.onCreateOptionsMenu(menu, inflater); - SystemServiceHelper.showIM(getActivity(), editText); - } - - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - Logger.debug("onCreateView"); - getWorld().getPostState().setListener(this); - View v = inflater.inflate(R.layout.fragment_post, null); - buttonTweet = getTweetButton(v); - buttonTweet.setOnClickListener(this); - editText = getEditText(v); - textViewCount = getCountTextView(v); - int textSize = UserPreferenceHelper.getInstance().getTextSize(); - editText.addTextChangedListener(this); - editText.setOnFocusChangeListener(this); - editText.setTextSize(textSize + 4); - editText.setMovementMethod(new ArrowKeyMovementMethod() { - @Override - protected boolean right(@NonNull TextView widget, Spannable buffer) { - //Don't back to Home - return widget.getSelectionEnd() == widget.length() || super.right(widget, buffer); - } - }); - ImageButton imageButtonDeleteText = (ImageButton) v.findViewById(R.id.button_post_delete); - imageButtonDeleteText.setOnClickListener(this); - ImageButton imageButtonMedia = (ImageButton) v.findViewById(R.id.button_post_media); - imageButtonMedia.setOnClickListener(this); - //Reply view - viewGroupReply = getReplyViewGroup(v); - ImageButton imageButtonDeleteReply = (ImageButton) viewGroupReply.findViewById(R.id.button_post_reply_delete); - imageButtonDeleteReply.setOnClickListener(this); - //Media view - viewGroupMedia = getMediaViewGroup(v); - ImageView imageViewMedia = (ImageView) viewGroupMedia.findViewById(R.id.image_post_media); - ImageButton imageButtonDeleteMedia = (ImageButton) viewGroupMedia.findViewById(R.id.button_post_media_delete); - imageViewMedia.setOnClickListener(this); - imageButtonDeleteMedia.setOnClickListener(this); - editText.requestFocus(); - return v; - } - - @Override - public void onDestroyView() { - Logger.debug("onDestroyView"); - super.onDestroyView(); - setStateFromView(); - getWorld().getPostState().removeListener(); - } - - @Override - public void onViewStateRestored(Bundle savedInstanceState) { - Logger.debug("onViewStateRestored"); - super.onViewStateRestored(savedInstanceState); - PostState state = getWorld().getPostState(); - onPostStateChange(state); - } - - private void deletePost() { - editText.setText(""); - getWorld().getPostState().beginTransaction().setText("").setCursor(0).commit(); - deleteReply(); - } - - private void deleteReply() { - viewGroupReply.setVisibility(View.GONE); - getWorld().getPostState().beginTransaction().setInReplyTo(null).commit(); - } - - private void displayImage() { - Intent intent = new Intent(); - intent.setAction(Intent.ACTION_VIEW); - intent.addCategory(Intent.CATEGORY_DEFAULT); - intent.setDataAndType(Uri.fromFile(new File(getWorld().getPostState().getMediaFilePath())), "image/*"); - IntentUtils.startActivityIfFound(getActivity(), intent); - } - - private TextView getCountTextView(View v) { - return (TextView) v.findViewById(R.id.post_text_count); - } - - private EditText getEditText(View v) { - return (EditText) v.findViewById(R.id.post_edit_text); - } - - private ViewGroup getMediaViewGroup(View v) { - return (ViewGroup) v.findViewById(R.id.post_media_parent); - } - - private ViewGroup getReplyViewGroup(View v) { - return (ViewGroup) v.findViewById(R.id.post_inreplyto_parent); - } - - private Button getTweetButton(View v) { - return (Button) v.findViewById(R.id.button_post_tweet); - } - - private void removeImage() { - SystemServiceHelper.hideIM(getActivity(), editText); - viewGroupMedia.setVisibility(View.GONE); - ((ImageView) viewGroupMedia.findViewById(R.id.image_post_media)).setImageBitmap(null); - getWorld().getPostState().beginTransaction().setMediaFilePath("").commit(); - } - - private void setImage() { - setStateFromView(); - SystemServiceHelper.hideIM(getActivity(), editText); - - Intent intent = new Intent(Intent.ACTION_PICK); - intent.setType("image/*"); - IntentUtils.startActivityForResultIfFound(getActivity(), intent, MainActivity.REQUEST_GET_PICTURE_FROM_GALLERY); - } - - private void setStateFromView() { - PostState state = getWorld().getPostState(); - state.removeListener(); - state.beginTransaction() - .setText(editText.getText().toString()) - .setSelection(editText.getSelectionStart(), editText.getSelectionEnd()) - .commit(); - state.setListener(this); - } - - private void submitPost() { - SystemServiceHelper.hideIM(getActivity(), editText); - setStateFromView(); - PostState state = getWorld().getPostState(); - MainActivity mainActivity = (MainActivity) getActivity(); - boolean resizeFlag = UserPreferenceHelper.getInstance().get(R.string.key_setting_resize_post_image, false); - new Tweets.CreateTask(getWorld().getAccount(), state.toStatusUpdate(), state.getMediaFilePath(), resizeFlag) - .onDoneUI(t -> { - getWorld().notify(R.string.notice_tweet_succeeded); - getWorld().getPostState().beginTransaction().clear().commit(); - }) - .onFail(e -> getWorld().notifyError(R.string.notice_tweet_failed, e)) - .execute(); - mainActivity.openHomePage(); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/page/PostFragment.kt b/app/src/main/java/net/lacolaco/smileessence/view/page/PostFragment.kt new file mode 100644 index 00000000..8afeadd1 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/page/PostFragment.kt @@ -0,0 +1,304 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.page + +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import android.support.v4.content.ContextCompat +import android.text.Editable +import android.text.Spannable +import android.text.TextUtils +import android.text.TextWatcher +import android.text.method.ArrowKeyMovementMethod +import android.view.* +import android.widget.* +import com.twitter.Validator +import net.lacolaco.smileessence.R +import net.lacolaco.smileessence.World +import net.lacolaco.smileessence.activity.MainActivity +import net.lacolaco.smileessence.data.PostState +import net.lacolaco.smileessence.entity.Tweet +import net.lacolaco.smileessence.logging.Logger +import net.lacolaco.smileessence.preference.UserPreferenceHelper +import net.lacolaco.smileessence.twitter.task.Tweets +import net.lacolaco.smileessence.util.BitmapThumbnailTask +import net.lacolaco.smileessence.util.IntentUtils +import net.lacolaco.smileessence.util.SystemServiceHelper +import net.lacolaco.smileessence.util.UIHandler +import net.lacolaco.smileessence.view.Partials + +import java.io.File + +class PostFragment : PageFragment(), TextWatcher, View.OnFocusChangeListener, View.OnClickListener, PostState.OnPostStateChangeListener { + private var editText: EditText? = null + private var textViewCount: TextView? = null + private var buttonTweet: Button? = null + private var viewGroupReply: ViewGroup? = null + private var viewGroupMedia: ViewGroup? = null + + override fun refresh() {} + + // --------------------- Interface OnClickListener --------------------- + + override fun onClick(v: View) { + when (v.id) { + R.id.button_post_delete -> { + deletePost() + } + R.id.button_post_media -> { + setImage() + } + R.id.button_post_tweet -> { + submitPost() + } + R.id.button_post_reply_delete -> { + deleteReply() + } + R.id.button_post_media_delete -> { + removeImage() + } + R.id.image_post_media -> { + displayImage() + } + } + } + + // --------------------- Interface OnFocusChangeListener --------------------- + + override fun onFocusChange(v: View, hasFocus: Boolean) { + if (hasFocus) { + SystemServiceHelper.showIM(activity, editText) + } else { + SystemServiceHelper.hideIM(activity, editText) + } + } + + // --------------------- Interface OnPostStateChangeListener --------------------- + + + override fun onPostStateChange(postState: PostState) { + Logger.debug("onPostStateChange") + val activity = activity as MainActivity + if (editText != null) { + val start = postState.selectionStart + val end = postState.selectionEnd + editText!!.removeTextChangedListener(this) + editText!!.setTextKeepState(postState.text) + editText!!.addTextChangedListener(this) + updateTextCount(editText!!.text) + UIHandler().postAtFrontOfQueue { editText!!.setSelection(start, end) } + } + if (viewGroupReply != null) { + if (postState.inReplyTo != null) { + viewGroupReply!!.visibility = View.VISIBLE + val imageButtonDeleteReply = viewGroupReply!!.findViewById(R.id.button_post_reply_delete) as ImageButton + imageButtonDeleteReply.setOnClickListener(this) + + val tweet = postState.inReplyTo + var header = viewGroupReply!!.findViewById(R.id.layout_post_reply_status) + header = Partials.getTweetView(tweet!!, activity, header, true) + header.setBackgroundColor(ContextCompat.getColor(getActivity(), R.color.transparent)) + header.isClickable = false + } else { + viewGroupReply!!.visibility = View.GONE + } + } + if (viewGroupMedia != null) { + val imageViewMedia = viewGroupMedia!!.findViewById(R.id.image_post_media) as ImageView + if (TextUtils.isEmpty(postState.mediaFilePath)) { + viewGroupMedia!!.visibility = View.GONE + } else { + viewGroupMedia!!.visibility = View.VISIBLE + + } + BitmapThumbnailTask(postState.mediaFilePath, imageViewMedia).execute() + } + } + + // --------------------- Interface TextWatcher --------------------- + + override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {} + + override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { + updateTextCount(s) + } + + private fun updateTextCount(s: CharSequence) { + val validator = Validator() + var remainingCount = 140 - validator.getTweetLength(s.toString()) + if (!TextUtils.isEmpty(world.postState.mediaFilePath)) { + remainingCount -= validator.shortUrlLength + } + textViewCount!!.text = remainingCount.toString() + if (remainingCount == 140 || remainingCount < 0) { + textViewCount!!.setTextColor(ContextCompat.getColor(activity, R.color.red)) + } else { + textViewCount!!.setTextAppearance(activity, android.R.style.TextAppearance_Widget_TextView) + } + setStateFromView() + } + + override fun afterTextChanged(s: Editable) {} + + // ------------------------ OVERRIDE METHODS ------------------------ + + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + super.onCreateOptionsMenu(menu, inflater) + SystemServiceHelper.showIM(activity, editText) + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + Logger.debug("onCreateView") + setHasOptionsMenu(true) + world.postState.setListener(this) + val v = inflater.inflate(R.layout.fragment_post, container, false) + buttonTweet = getTweetButton(v) + buttonTweet!!.setOnClickListener(this) + editText = getEditText(v) + textViewCount = getCountTextView(v) + val textSize = UserPreferenceHelper.instance.textSize + editText!!.addTextChangedListener(this) + editText!!.onFocusChangeListener = this + editText!!.textSize = (textSize + 4).toFloat() + editText!!.movementMethod = object : ArrowKeyMovementMethod() { + override fun right(widget: TextView, buffer: Spannable): Boolean { + //Don't back to Home + return widget.selectionEnd == widget.length() || super.right(widget, buffer) + } + } + val imageButtonDeleteText = v.findViewById(R.id.button_post_delete) as ImageButton + imageButtonDeleteText.setOnClickListener(this) + val imageButtonMedia = v.findViewById(R.id.button_post_media) as ImageButton + imageButtonMedia.setOnClickListener(this) + //Reply view + viewGroupReply = getReplyViewGroup(v) + val imageButtonDeleteReply = viewGroupReply!!.findViewById(R.id.button_post_reply_delete) as ImageButton + imageButtonDeleteReply.setOnClickListener(this) + //Media view + viewGroupMedia = getMediaViewGroup(v) + val imageViewMedia = viewGroupMedia!!.findViewById(R.id.image_post_media) as ImageView + val imageButtonDeleteMedia = viewGroupMedia!!.findViewById(R.id.button_post_media_delete) as ImageButton + imageViewMedia.setOnClickListener(this) + imageButtonDeleteMedia.setOnClickListener(this) + editText!!.requestFocus() + return v + } + + override fun onDestroyView() { + Logger.debug("onDestroyView") + super.onDestroyView() + setStateFromView() + world.postState.removeListener() + } + + override fun onViewStateRestored(savedInstanceState: Bundle?) { + Logger.debug("onViewStateRestored") + super.onViewStateRestored(savedInstanceState) + val state = world.postState + onPostStateChange(state) + } + + private fun deletePost() { + editText!!.setText("") + world.postState.beginTransaction().setText("").setCursor(0).commit() + deleteReply() + } + + private fun deleteReply() { + viewGroupReply!!.visibility = View.GONE + world.postState.beginTransaction().setInReplyTo(null).commit() + } + + private fun displayImage() { + val intent = Intent() + intent.action = Intent.ACTION_VIEW + intent.addCategory(Intent.CATEGORY_DEFAULT) + intent.setDataAndType(Uri.fromFile(File(world.postState.mediaFilePath)), "image/*") + IntentUtils.startActivityIfFound(activity, intent) + } + + private fun getCountTextView(v: View): TextView { + return v.findViewById(R.id.post_text_count) as TextView + } + + private fun getEditText(v: View): EditText { + return v.findViewById(R.id.post_edit_text) as EditText + } + + private fun getMediaViewGroup(v: View): ViewGroup { + return v.findViewById(R.id.post_media_parent) as ViewGroup + } + + private fun getReplyViewGroup(v: View): ViewGroup { + return v.findViewById(R.id.post_inreplyto_parent) as ViewGroup + } + + private fun getTweetButton(v: View): Button { + return v.findViewById(R.id.button_post_tweet) as Button + } + + private fun removeImage() { + SystemServiceHelper.hideIM(activity, editText) + viewGroupMedia!!.visibility = View.GONE + (viewGroupMedia!!.findViewById(R.id.image_post_media) as ImageView).setImageBitmap(null) + world.postState.beginTransaction().setMediaFilePath("").commit() + } + + private fun setImage() { + setStateFromView() + SystemServiceHelper.hideIM(activity, editText) + + val intent = Intent(Intent.ACTION_PICK) + intent.type = "image/*" + IntentUtils.startActivityForResultIfFound(activity, intent, MainActivity.REQUEST_GET_PICTURE_FROM_GALLERY) + } + + private fun setStateFromView() { + val state = world.postState + state.removeListener() + state.beginTransaction() + .setText(editText!!.text.toString()) + .setSelection(editText!!.selectionStart, editText!!.selectionEnd) + .commit() + state.setListener(this) + } + + private fun submitPost() { + SystemServiceHelper.hideIM(activity, editText) + setStateFromView() + val state = world.postState + val mainActivity = activity as MainActivity + val resizeFlag = UserPreferenceHelper.instance.get(R.string.key_setting_resize_post_image, false) + Tweets.CreateTask(world.account, state.toStatusUpdate(), state.mediaFilePath, resizeFlag) + .onDoneUI { t -> + world.notify(R.string.notice_tweet_succeeded) + world.postState.beginTransaction().clear().commit() + } + .onFail { e -> world.notifyError(R.string.notice_tweet_failed, e) } + .execute() + mainActivity.openHomePage() + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/page/SearchFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/page/SearchFragment.java deleted file mode 100644 index 84d10c21..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/page/SearchFragment.java +++ /dev/null @@ -1,321 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.view.page; - -import android.app.AlertDialog; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.text.Spannable; -import android.text.TextUtils; -import android.text.method.ArrowKeyMovementMethod; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.inputmethod.EditorInfo; -import android.widget.EditText; -import android.widget.ImageButton; -import android.widget.ListView; -import android.widget.TextView; -import com.handmark.pulltorefresh.library.PullToRefreshBase; -import com.handmark.pulltorefresh.library.PullToRefreshListView; -import net.lacolaco.smileessence.R; -import net.lacolaco.smileessence.activity.MainActivity; -import net.lacolaco.smileessence.entity.SavedSearch; -import net.lacolaco.smileessence.preference.InternalPreferenceHelper; -import net.lacolaco.smileessence.twitter.task.Searches; -import net.lacolaco.smileessence.util.ListUtils; -import net.lacolaco.smileessence.util.SystemServiceHelper; -import net.lacolaco.smileessence.util.UIHandler; -import net.lacolaco.smileessence.view.adapter.TimelineAdapter; -import net.lacolaco.smileessence.view.dialog.ConfirmDialogFragment; -import twitter4j.Query; - -import java.util.ArrayList; -import java.util.List; - -public class SearchFragment extends CustomListFragment implements View.OnClickListener, View.OnLongClickListener, - View.OnFocusChangeListener { - - // ------------------------------ FIELDS ------------------------------ - - private String queryString; - private TimelineAdapter adapter; - private EditText editText; - - // --------------------- GETTER / SETTER METHODS --------------------- - - @Override - protected PullToRefreshBase.Mode getRefreshMode() { - return PullToRefreshBase.Mode.BOTH; - } - - // ------------------------ INTERFACE METHODS ------------------------ - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setHasOptionsMenu(true); - - queryString = InternalPreferenceHelper.getInstance().get(R.string.key_last_used_search_query, ""); - android.app.Activity activity = getActivity(); - adapter = new TimelineAdapter(activity); - setAdapter(adapter); - - refresh(); - } - - @Override - public void refresh() { //TODO - if (!TextUtils.isEmpty(queryString)) { - startSearch(queryString); - } - } - - // --------------------- Interface OnClickListener --------------------- - - @Override - public void onClick(View v) { - switch (v.getId()) { - case R.id.button_search_queries: { - openSearchQueryDialog(); - break; - } - case R.id.button_search_execute: { - search(); - break; - } - case R.id.button_search_save: { - saveQuery(); - } - } - } - - @Override - public boolean onLongClick(View v) { - switch (v.getId()) { - case R.id.button_search_save: { - String text = editText.getText().toString(); - for (SavedSearch ss : getWorld().getSavedSearches()) { - if (ss.getQuery().equals(text)) { - ConfirmDialogFragment.show(getActivity(), getString(R.string.dialog_confirm_delete_query), () -> new Searches.DestroySavedSearchTask(getWorld().getAccount(), ss.getId()) - .onDoneUI(x -> { - getWorld().notify(R.string.notice_search_query_deleted); - getWorld().refreshSavedSearches(); - }) - .onFailUI(x -> getWorld().notify("unable to delete search query")) - .execute(), false); - break; - } - } - return true; - } - } - return false; - } - - // --------------------- Interface OnFocusChangeListener --------------------- - - @Override - public void onFocusChange(View v, boolean hasFocus) { - if (!hasFocus) { - SystemServiceHelper.hideIM(getActivity(), editText); - } - } - - // --------------------- Interface OnRefreshListener2 --------------------- - - @Override - public void onPullDownToRefresh(final PullToRefreshBase refreshView) { - if (TextUtils.isEmpty(queryString)) { - new UIHandler().post(() -> { - notifyTextEmpty(); - refreshView.onRefreshComplete(); - }); - return; - } - final Query query = new Query(); - query.setQuery(queryString); - query.setCount(200); - query.setResultType(Query.RECENT); - if (adapter.getCount() > 0) { - query.setSinceId(adapter.getTopID()); - } - runRefreshTask(query, () -> { - updateListViewWithNotice(refreshView.getRefreshableView(), true); - refreshView.onRefreshComplete(); - }); - } - - @Override - public void onPullUpToRefresh(final PullToRefreshBase refreshView) { - if (TextUtils.isEmpty(queryString)) { - new UIHandler().post(() -> { - notifyTextEmpty(); - refreshView.onRefreshComplete(); - }); - return; - } - final Query query = new Query(); - query.setQuery(queryString); - query.setCount(200); - query.setResultType(Query.RECENT); - if (adapter.getCount() > 0) { - query.setMaxId(adapter.getLastID() - 1); - } - runRefreshTask(query, () -> { - updateListViewWithNotice(refreshView.getRefreshableView(), false); - refreshView.onRefreshComplete(); - }); - } - - // ------------------------ OVERRIDE METHODS ------------------------ - - @Override - protected PullToRefreshListView getListView(View page) { - return (PullToRefreshListView) page.findViewById(R.id.listview_search); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View page = inflater.inflate(R.layout.fragment_search, container, false); - PullToRefreshListView listView = getListView(page); - listView.setAdapter(adapter); - listView.setOnScrollListener(this); - listView.setOnRefreshListener(this); - listView.setMode(getRefreshMode()); - ImageButton buttonQueries = getQueriesButton(page); - buttonQueries.setOnClickListener(this); - ImageButton buttonExecute = getExecuteButton(page); - buttonExecute.setOnClickListener(this); - ImageButton buttonSave = getSaveButton(page); - buttonSave.setOnClickListener(this); - editText = getEditText(page); - editText.setOnFocusChangeListener(this); - editText.setText(queryString); - editText.setOnEditorActionListener((textView, i, keyEvent) -> { - if (i == EditorInfo.IME_ACTION_SEARCH || - keyEvent != null && - keyEvent.getAction() == KeyEvent.ACTION_DOWN && - keyEvent.getKeyCode() == KeyEvent.KEYCODE_ENTER) { - search(); - } - return true; - }); - editText.setMovementMethod(new ArrowKeyMovementMethod() { - @Override - protected boolean right(@NonNull TextView widget, Spannable buffer) { - //Don't move page - return widget.getSelectionEnd() == widget.length() || super.right(widget, buffer); - } - - @Override - protected boolean left(@NonNull TextView widget, Spannable buffer) { - //Don't move page - return widget.getSelectionStart() == 0 || super.left(widget, buffer); - } - }); - return page; - } - - private EditText getEditText(View page) { - return (EditText) page.findViewById(R.id.edittext_search); - } - - private ImageButton getExecuteButton(View page) { - return (ImageButton) page.findViewById(R.id.button_search_execute); - } - - private ImageButton getQueriesButton(View page) { - return (ImageButton) page.findViewById(R.id.button_search_queries); - } - - private ImageButton getSaveButton(View page) { - return (ImageButton) page.findViewById(R.id.button_search_save); - } - - private void notifyTextEmpty() { - getWorld().notifyError(R.string.notice_search_text_empty); - } - - private void openSearchQueryDialog() { - List sss = new ArrayList<>(getWorld().getSavedSearches()); - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - builder.setItems(ListUtils.map(sss, SavedSearch::getQuery).toArray(new String[]{}), (dialog, which) -> { - SavedSearch ss = sss.get(which); - ((MainActivity) getActivity()).openSearchPage(ss.getQuery()); - }); - AlertDialog dialog = builder.create(); - dialog.show(); - } - - private void saveQuery() { - String text = editText.getText().toString(); - if (TextUtils.isEmpty(text)) { - getWorld().notifyError(R.string.notice_query_is_empty); - } else { - new Searches.CreateSavedSearchTask(getWorld().getAccount(), text).onDoneUI(cb -> { - getWorld().notify(R.string.notice_query_saved); - getWorld().refreshSavedSearches(); - }).onFailUI(ex -> getWorld().notifyError("Query is not saved")).execute(); - } - } - - private void search() { - if (editText != null) { - String text = editText.getText().toString(); - if (TextUtils.isEmpty(text)) { - getWorld().notifyError(R.string.notice_query_is_empty); - } else { - startSearch(text); - SystemServiceHelper.hideIM(getActivity(), editText); - } - } - } - - public void startSearch(final String queryString) { - InternalPreferenceHelper.getInstance().set(R.string.key_last_used_search_query, queryString); - if (editText != null) - editText.setText(queryString); - this.queryString = queryString; - adapter.clear(); - adapter.updateForce(); - if (!TextUtils.isEmpty(queryString)) { - final Query query = new Query(); - query.setQuery(queryString); - query.setCount(200); - query.setResultType(Query.RECENT); - runRefreshTask(query, adapter::updateForce); - } - } - - private void runRefreshTask(Query query, Runnable onFinish) { - new Searches.SearchTask(getWorld().getAccount(), query) - .onFail(x -> getWorld().notifyError(R.string.notice_error_search)) - .onDoneUI(tweets -> adapter.addAll(ListUtils.filter(tweets, t -> !t.isRetweet()))) - .onFinishUI(onFinish) - .execute(); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/page/SearchFragment.kt b/app/src/main/java/net/lacolaco/smileessence/view/page/SearchFragment.kt new file mode 100644 index 00000000..de06a133 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/page/SearchFragment.kt @@ -0,0 +1,299 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.page + +import android.app.AlertDialog +import android.os.Bundle +import android.text.Spannable +import android.text.TextUtils +import android.text.method.ArrowKeyMovementMethod +import android.view.KeyEvent +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.inputmethod.EditorInfo +import android.widget.EditText +import android.widget.ImageButton +import android.widget.ListView +import android.widget.TextView +import com.handmark.pulltorefresh.library.PullToRefreshBase +import com.handmark.pulltorefresh.library.PullToRefreshListView +import net.lacolaco.smileessence.R +import net.lacolaco.smileessence.activity.MainActivity +import net.lacolaco.smileessence.preference.InternalPreferenceHelper +import net.lacolaco.smileessence.twitter.task.Searches +import net.lacolaco.smileessence.util.SystemServiceHelper +import net.lacolaco.smileessence.util.UIHandler +import net.lacolaco.smileessence.view.adapter.TimelineAdapter +import net.lacolaco.smileessence.view.dialog.ConfirmDialogFragment +import twitter4j.Query + +import java.util.ArrayList + +class SearchFragment : CustomListFragment(), View.OnClickListener, View.OnLongClickListener, View.OnFocusChangeListener { + + // ------------------------------ FIELDS ------------------------------ + + private lateinit var queryString: String + private var editText: EditText? = null + + // --------------------- GETTER / SETTER METHODS --------------------- + + override val refreshMode: PullToRefreshBase.Mode + get() = PullToRefreshBase.Mode.BOTH + + // ------------------------ INTERFACE METHODS ------------------------ + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setHasOptionsMenu(true) + + queryString = InternalPreferenceHelper.instance.get(R.string.key_last_used_search_query, "") + adapter = TimelineAdapter(activity) + + refresh() + } + + override fun refresh() { //TODO + if (!TextUtils.isEmpty(queryString)) { + startSearch(queryString) + } + } + + // --------------------- Interface OnClickListener --------------------- + + override fun onClick(v: View) { + when (v.id) { + R.id.button_search_queries -> { + openSearchQueryDialog() + } + R.id.button_search_execute -> { + search() + } + R.id.button_search_save -> { + saveQuery() + } + } + } + + override fun onLongClick(v: View): Boolean { + when (v.id) { + R.id.button_search_save -> { + val text = editText!!.text.toString() + for (ss in world.savedSearches.values) { + if (ss.query == text) { + ConfirmDialogFragment.show(activity, getString(R.string.dialog_confirm_delete_query), { + Searches.DestroySavedSearchTask(world.account, ss.id) + .onDoneUI { x -> + world.notify(R.string.notice_search_query_deleted) + world.refreshSavedSearches() + } + .onFailUI { x -> world.notify("unable to delete search query") } + .execute() + }, false) + break + } + } + return true + } + } + return false + } + + // --------------------- Interface OnFocusChangeListener --------------------- + + override fun onFocusChange(v: View, hasFocus: Boolean) { + if (!hasFocus) { + SystemServiceHelper.hideIM(activity, editText) + } + } + + // --------------------- Interface OnRefreshListener2 --------------------- + + override fun onPullDownToRefresh(refreshView: PullToRefreshBase) { + if (TextUtils.isEmpty(queryString)) { + UIHandler().post { + notifyTextEmpty() + refreshView.onRefreshComplete() + } + return + } + val query = Query() + query.query = queryString + query.count = 200 + query.resultType = Query.RECENT + if (adapter.count > 0) { + query.sinceId = adapter.topID + } + runRefreshTask(query, { + updateListViewWithNotice(refreshView.refreshableView, true) + refreshView.onRefreshComplete() + }) + } + + override fun onPullUpToRefresh(refreshView: PullToRefreshBase) { + if (TextUtils.isEmpty(queryString)) { + UIHandler().post { + notifyTextEmpty() + refreshView.onRefreshComplete() + } + return + } + val query = Query() + query.query = queryString + query.count = 200 + query.resultType = Query.RECENT + if (adapter.count > 0) { + query.maxId = adapter.lastID - 1 + } + runRefreshTask(query, { + updateListViewWithNotice(refreshView.refreshableView, false) + refreshView.onRefreshComplete() + }) + } + + // ------------------------ OVERRIDE METHODS ------------------------ + + override fun getListView(page: View): PullToRefreshListView { + return page.findViewById(R.id.listview_search) as PullToRefreshListView + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup, savedInstanceState: Bundle?): View { + val page = inflater.inflate(R.layout.fragment_search, container, false) + val listView = getListView(page) + listView.setAdapter(adapter) + listView.setOnScrollListener(this) + listView.setOnRefreshListener(this) + listView.mode = refreshMode + val buttonQueries = getQueriesButton(page) + buttonQueries.setOnClickListener(this) + val buttonExecute = getExecuteButton(page) + buttonExecute.setOnClickListener(this) + val buttonSave = getSaveButton(page) + buttonSave.setOnClickListener(this) + editText = getEditText(page) + editText!!.onFocusChangeListener = this + editText!!.setText(queryString) + editText!!.setOnEditorActionListener { textView, i, keyEvent -> + if (i == EditorInfo.IME_ACTION_SEARCH || keyEvent != null && + keyEvent.action == KeyEvent.ACTION_DOWN && + keyEvent.keyCode == KeyEvent.KEYCODE_ENTER) { + search() + } + true + } + editText!!.movementMethod = object : ArrowKeyMovementMethod() { + override fun right(widget: TextView, buffer: Spannable): Boolean { + //Don't move page + return widget.selectionEnd == widget.length() || super.right(widget, buffer) + } + + override fun left(widget: TextView, buffer: Spannable): Boolean { + //Don't move page + return widget.selectionStart == 0 || super.left(widget, buffer) + } + } + return page + } + + private fun getEditText(page: View): EditText { + return page.findViewById(R.id.edittext_search) as EditText + } + + private fun getExecuteButton(page: View): ImageButton { + return page.findViewById(R.id.button_search_execute) as ImageButton + } + + private fun getQueriesButton(page: View): ImageButton { + return page.findViewById(R.id.button_search_queries) as ImageButton + } + + private fun getSaveButton(page: View): ImageButton { + return page.findViewById(R.id.button_search_save) as ImageButton + } + + private fun notifyTextEmpty() { + world.notifyError(R.string.notice_search_text_empty) + } + + private fun openSearchQueryDialog() { + val sss = ArrayList(world.savedSearches.values) + val builder = AlertDialog.Builder(activity) + builder.setItems(sss.map { it.query }.toTypedArray()) { dialog, which -> + val ss = sss[which] + (activity as MainActivity).openSearchPage(ss.query) + } + val dialog = builder.create() + dialog.show() + } + + private fun saveQuery() { + val text = editText!!.text.toString() + if (TextUtils.isEmpty(text)) { + world.notifyError(R.string.notice_query_is_empty) + } else { + Searches.CreateSavedSearchTask(world.account, text).onDoneUI { cb -> + world.notify(R.string.notice_query_saved) + world.refreshSavedSearches() + }.onFailUI { ex -> world.notifyError("Query is not saved") }.execute() + } + } + + private fun search() { + if (editText != null) { + val text = editText!!.text.toString() + if (TextUtils.isEmpty(text)) { + world.notifyError(R.string.notice_query_is_empty) + } else { + startSearch(text) + SystemServiceHelper.hideIM(activity, editText) + } + } + } + + fun startSearch(queryString: String) { + InternalPreferenceHelper.instance.set(R.string.key_last_used_search_query, queryString) + if (editText != null) + editText!!.setText(queryString) + this.queryString = queryString + adapter.clear() + adapter.updateForce() + if (!TextUtils.isEmpty(queryString)) { + val query = Query() + query.query = queryString + query.count = 200 + query.resultType = Query.RECENT + runRefreshTask(query) { adapter.updateForce() } + } + } + + private fun runRefreshTask(query: Query, onFinish: () -> Unit) { + Searches.SearchTask(world.account, query) + .onFail { x -> world.notifyError(R.string.notice_error_search) } + .onDoneUI { tweets -> adapter.addAll(tweets.filter { t -> !t.isRetweet }) } + .onFinishUI(onFinish) + .execute() + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/page/UserListFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/page/UserListFragment.java deleted file mode 100644 index 3d19c5d6..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/page/UserListFragment.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence.view.page; - -import android.app.AlertDialog; -import android.os.Bundle; -import android.text.TextUtils; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageButton; -import android.widget.ListView; -import android.widget.TextView; -import com.handmark.pulltorefresh.library.PullToRefreshBase; -import com.handmark.pulltorefresh.library.PullToRefreshListView; -import net.lacolaco.smileessence.Application; -import net.lacolaco.smileessence.R; -import net.lacolaco.smileessence.activity.MainActivity; -import net.lacolaco.smileessence.entity.Tweet; -import net.lacolaco.smileessence.preference.InternalPreferenceHelper; -import net.lacolaco.smileessence.twitter.task.TimelineTask; -import net.lacolaco.smileessence.twitter.task.Timelines; -import net.lacolaco.smileessence.util.UIHandler; -import net.lacolaco.smileessence.view.adapter.TimelineAdapter; - -public class UserListFragment extends CustomListFragment implements View.OnClickListener { - private TextView textListName; - private String listFullName; - - @Override - protected PullToRefreshBase.Mode getRefreshMode() { - return PullToRefreshBase.Mode.BOTH; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - TimelineAdapter adapter = new TimelineAdapter(getActivity()); - setAdapter(adapter); - - refresh(); - } - - @Override - public void refresh() {//TODO - String lastUserList = InternalPreferenceHelper.getInstance().get(R.string.key_last_used_user_list, ""); - if (!TextUtils.isEmpty(lastUserList)) { - startUserList(lastUserList); - } - } - - @Override - public void onClick(View v) { - int id = v.getId(); - switch (id) { - case R.id.button_userlist_lists: { - openUserListsDialog(); - break; - } - } - } - - @Override - public void onPullDownToRefresh(final PullToRefreshBase refreshView) { - if (listFullName == null) { - new UIHandler().post(() -> { - notifyTextEmpty(); - refreshView.onRefreshComplete(); - }); - return; - } - runRefreshTask( - new Timelines.UserListStatusesTask(getWorld().getAccount(), listFullName) - .setSinceId(getAdapter().getTopID()), - () -> { - updateListViewWithNotice(refreshView.getRefreshableView(), true); - refreshView.onRefreshComplete(); - }); - } - - @Override - public void onPullUpToRefresh(final PullToRefreshBase refreshView) { - if (listFullName == null) { - new UIHandler().post(() -> { - notifyTextEmpty(); - refreshView.onRefreshComplete(); - }); - return; - } - runRefreshTask( - new Timelines.UserListStatusesTask(getWorld().getAccount(), listFullName) - .setMaxId(getAdapter().getLastID() - 1), - () -> { - updateListViewWithNotice(refreshView.getRefreshableView(), false); - refreshView.onRefreshComplete(); - }); - } - - // ------------------------ OVERRIDE METHODS ------------------------ - - @Override - protected PullToRefreshListView getListView(View page) { - return (PullToRefreshListView) page.findViewById(R.id.listview_userlist); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View page = inflater.inflate(R.layout.fragment_userlist, container, false); - PullToRefreshListView listView = getListView(page); - TimelineAdapter adapter = getAdapter(); - listView.setAdapter(adapter); - listView.setOnScrollListener(this); - listView.setOnRefreshListener(this); - listView.setMode(getRefreshMode()); - ImageButton buttonUserLists = getUserListsButton(page); - buttonUserLists.setOnClickListener(this); - textListName = getTextListName(page); - textListName.setText(listFullName != null ? listFullName : ""); - return page; - } - - private TextView getTextListName(View page) { - return (TextView) page.findViewById(R.id.textview_userlist_name); - } - - private ImageButton getUserListsButton(View page) { - return (ImageButton) page.findViewById(R.id.button_userlist_lists); - } - - private void notifyTextEmpty() { - getWorld().notifyError(R.string.notice_userlist_not_selected); - } - - private void openUserListsDialog() { - final String[] ary = getWorld().getListSubscriptions().toArray(new String[]{}); - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - builder.setTitle(R.string.dialog_title_select_userlist) - .setItems(ary, (dialog, which) -> { - MainActivity activity = (MainActivity) getActivity(); - activity.openUserListPage(ary[which]); - textListName.setText(ary[which]); - }); - AlertDialog dialog = builder.create(); - dialog.show(); - } - - public void startUserList(String listFullName) { - InternalPreferenceHelper.getInstance().set(R.string.key_last_used_user_list, listFullName); - final TimelineAdapter adapter = getAdapter(); - this.listFullName = listFullName; - adapter.clear(); - adapter.updateForce(); - runRefreshTask( - new Timelines.UserListStatusesTask(getWorld().getAccount(), listFullName), - adapter::updateForce); - } - - private void runRefreshTask(TimelineTask task, Runnable onFinish) { - final TimelineAdapter adapter = getAdapter(); - task - .setCount(200) - .onFail(x -> getWorld().notifyError(R.string.notice_error_get_list)) - .onDoneUI(tweets -> { - getWorld().addTweetAll(tweets); - adapter.addAll(tweets); - }) - .onFinishUI(onFinish) - .execute(); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/page/UserListFragment.kt b/app/src/main/java/net/lacolaco/smileessence/view/page/UserListFragment.kt new file mode 100644 index 00000000..3fb7ef49 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/page/UserListFragment.kt @@ -0,0 +1,179 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.page + +import android.app.AlertDialog +import android.os.Bundle +import android.text.TextUtils +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageButton +import android.widget.ListView +import android.widget.TextView +import com.handmark.pulltorefresh.library.PullToRefreshBase +import com.handmark.pulltorefresh.library.PullToRefreshListView +import net.lacolaco.smileessence.Application +import net.lacolaco.smileessence.R +import net.lacolaco.smileessence.activity.MainActivity +import net.lacolaco.smileessence.entity.Tweet +import net.lacolaco.smileessence.preference.InternalPreferenceHelper +import net.lacolaco.smileessence.twitter.task.TimelineTask +import net.lacolaco.smileessence.twitter.task.Timelines +import net.lacolaco.smileessence.util.UIHandler +import net.lacolaco.smileessence.view.adapter.TimelineAdapter + +class UserListFragment : CustomListFragment(), View.OnClickListener { + private var textListName: TextView? = null + private var listFullName: String? = null + + override val refreshMode: PullToRefreshBase.Mode + get() = PullToRefreshBase.Mode.BOTH + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + adapter = TimelineAdapter(activity) + + refresh() + } + + override fun refresh() {//TODO + val lastUserList = InternalPreferenceHelper.instance.get(R.string.key_last_used_user_list, "") + if (!TextUtils.isEmpty(lastUserList)) { + startUserList(lastUserList) + } + } + + override fun onClick(v: View) { + val id = v.id + when (id) { + R.id.button_userlist_lists -> { + openUserListsDialog() + } + } + } + + override fun onPullDownToRefresh(refreshView: PullToRefreshBase) { + if (listFullName == null) { + UIHandler().post { + notifyTextEmpty() + refreshView.onRefreshComplete() + } + return + } + runRefreshTask( + Timelines.UserListStatusesTask(world.account, listFullName!!) + .setSinceId(adapter.topID), + { + updateListViewWithNotice(refreshView.refreshableView, true) + refreshView.onRefreshComplete() + }) + } + + override fun onPullUpToRefresh(refreshView: PullToRefreshBase) { + if (listFullName == null) { + UIHandler().post { + notifyTextEmpty() + refreshView.onRefreshComplete() + } + return + } + runRefreshTask( + Timelines.UserListStatusesTask(world.account, listFullName!!) + .setMaxId(adapter.lastID - 1), + { + updateListViewWithNotice(refreshView.refreshableView, false) + refreshView.onRefreshComplete() + }) + } + + // ------------------------ OVERRIDE METHODS ------------------------ + + override fun getListView(page: View): PullToRefreshListView { + return page.findViewById(R.id.listview_userlist) as PullToRefreshListView + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup, savedInstanceState: Bundle?): View { + val page = inflater.inflate(R.layout.fragment_userlist, container, false) + val listView = getListView(page) + val adapter = adapter + listView.setAdapter(adapter) + listView.setOnScrollListener(this) + listView.setOnRefreshListener(this) + listView.mode = refreshMode + val buttonUserLists = getUserListsButton(page) + buttonUserLists.setOnClickListener(this) + textListName = getTextListName(page) + textListName!!.text = if (listFullName != null) listFullName else "" + return page + } + + private fun getTextListName(page: View): TextView { + return page.findViewById(R.id.textview_userlist_name) as TextView + } + + private fun getUserListsButton(page: View): ImageButton { + return page.findViewById(R.id.button_userlist_lists) as ImageButton + } + + private fun notifyTextEmpty() { + world.notifyError(R.string.notice_userlist_not_selected) + } + + private fun openUserListsDialog() { + val ary = world.listSubscriptions.toTypedArray() + val builder = AlertDialog.Builder(activity) + builder.setTitle(R.string.dialog_title_select_userlist) + .setItems(ary) { dialog, which -> + val activity = activity as MainActivity + activity.openUserListPage(ary[which]) + textListName!!.text = ary[which] + } + val dialog = builder.create() + dialog.show() + } + + fun startUserList(listFullName: String) { + InternalPreferenceHelper.instance.set(R.string.key_last_used_user_list, listFullName) + val adapter = adapter + this.listFullName = listFullName + adapter.clear() + adapter.updateForce() + runRefreshTask(Timelines.UserListStatusesTask(world.account, listFullName)) { adapter.updateForce() } + } + + private fun runRefreshTask(task: TimelineTask, onFinish: () -> Unit) { + val adapter = adapter + task + .setCount(200) + .onFail { x -> world.notifyError(R.string.notice_error_get_list) } + .onDoneUI { tweets -> + world.addTweetAll(tweets) + adapter.addAll(tweets) + } + .onFinishUI(onFinish) + .execute() + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/preference/IntegerEditTextPreference.java b/app/src/main/java/net/lacolaco/smileessence/view/preference/IntegerEditTextPreference.java deleted file mode 100644 index 88ad0879..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/preference/IntegerEditTextPreference.java +++ /dev/null @@ -1,36 +0,0 @@ -package net.lacolaco.smileessence.view.preference; - -import android.annotation.TargetApi; -import android.content.Context; -import android.os.Build; -import android.preference.EditTextPreference; -import android.util.AttributeSet; - -public class IntegerEditTextPreference extends EditTextPreference { - public IntegerEditTextPreference(Context context) { - super(context); - } - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - public IntegerEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - } - - public IntegerEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - } - - public IntegerEditTextPreference(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - protected boolean persistString(String value) { - return persistInt(Integer.valueOf(value)); - } - - @Override - protected String getPersistedString(String defaultReturnValue) { - return String.valueOf(getPersistedInt(-1)); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/preference/IntegerEditTextPreference.kt b/app/src/main/java/net/lacolaco/smileessence/view/preference/IntegerEditTextPreference.kt new file mode 100644 index 00000000..e6a23696 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/preference/IntegerEditTextPreference.kt @@ -0,0 +1,26 @@ +package net.lacolaco.smileessence.view.preference + +import android.annotation.TargetApi +import android.content.Context +import android.os.Build +import android.preference.EditTextPreference +import android.util.AttributeSet + +class IntegerEditTextPreference : EditTextPreference { + constructor(context: Context) : super(context) + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) + + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) + + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) + + override fun persistString(value: String): Boolean { + return persistInt(Integer.valueOf(value)!!) + } + + override fun getPersistedString(defaultReturnValue: String?): String { + return getPersistedInt(-1).toString() + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/preference/IntegerListPreference.java b/app/src/main/java/net/lacolaco/smileessence/view/preference/IntegerListPreference.java deleted file mode 100644 index f04a3b89..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/view/preference/IntegerListPreference.java +++ /dev/null @@ -1,37 +0,0 @@ -package net.lacolaco.smileessence.view.preference; - -import android.annotation.TargetApi; -import android.content.Context; -import android.os.Build; -import android.preference.ListPreference; -import android.util.AttributeSet; - -public class IntegerListPreference extends ListPreference { - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - public IntegerListPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - } - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - public IntegerListPreference(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - } - - public IntegerListPreference(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public IntegerListPreference(Context context) { - super(context); - } - - @Override - protected boolean persistString(String value) { - return persistInt(Integer.valueOf(value)); - } - - @Override - protected String getPersistedString(String defaultReturnValue) { - return String.valueOf(getPersistedInt(-1)); - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/preference/IntegerListPreference.kt b/app/src/main/java/net/lacolaco/smileessence/view/preference/IntegerListPreference.kt new file mode 100644 index 00000000..7dbe3297 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/preference/IntegerListPreference.kt @@ -0,0 +1,27 @@ +package net.lacolaco.smileessence.view.preference + +import android.annotation.TargetApi +import android.content.Context +import android.os.Build +import android.preference.ListPreference +import android.util.AttributeSet + +class IntegerListPreference : ListPreference { + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) + + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) + + constructor(context: Context) : super(context) + + override fun persistString(value: String): Boolean { + return persistInt(Integer.valueOf(value)!!) + } + + override fun getPersistedString(defaultReturnValue: String?): String { + return getPersistedInt(-1).toString() + } +} -- cgit v1.2.3